当你第一次启动一个Android程序的时候,一个被 称为"main"的线程就被自动创建了。它被称为主线程或者UI线程,它是非常重要的因为负责分发事件给对应的widget,还包含画图的事件。主线程贯 穿用户和Android widget的交互的整个过程。例如,你触摸了屏幕上的按钮(Button),UI线程派发(dispatch)触摸(touch)事件给 widget,widget设置为按下状态并向事件队列发送一个无效的请求。UI线程把这个请求弹出栈并且通知widget去重画它自己。
       
单线程模型导致Android程序低效。因为每次单线程去执行长时间的操作如网络请求,数据库查询和drawing
event(绘图事件),在这个过程中会阻塞程序的界面(UI)。当长时间的任务正在执行的时候,没有事件(Event)会被派发(dispatch),
包括drawing
event(绘图事件)。从用户的角度来看,改程序出现了终止。甚至更糟糕的是,如果UI程序被阻塞几秒后(大约5s)就会出现臭名昭著的ANR
对话框。
        如果想看一下有多糟糕,你可以写一个简单的带有按钮的程序,按钮的点击事件执行Thread.sleep(2000)代码。该按钮将会保持2秒的按下状态然后恢复正常的状态。这样很容易让用户感到程序很慢。
        现在你知道了一定避免在主线程中执行长时间的操作,你可能会使用额外的线程(后台线程或者工作线程)去执行操作。让我们来看看点击从网络下载图片到ImageView里的例子:
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
Bitmap b = loadImageFromNetwork();
mImageView.setImageBitmap(b);
}
}).start();
}
首先,代码看上去很好的解决我们的问题,因为它不会阻塞UI线程,不幸的是,它违背了单一线程模型:Android UI工具箱(toolkit)不是一个线程安全的,并且它总是被放在主线程上操作。
这个ImageView被一个工作线程操作,这导致非常不可思议的问题。跟踪和修复这样一个bug很难并且也耗时。
        Android提供了几种从其他线程访问主线程的方式。你可能已经很数量的使用他们,但是这里是齐全的列表:
以上任何一个类都能修正我们的代码:
public void onClick(View v) {
new Thread(new Runnable() {
public void run() {
final Bitmap b = loadImageFromNetwork();
mImageView.post(new Runnable() {
public void run() {
mImageView.setImageBitmap(b);
}
});
}
}).start();
}
不幸的是,这些类和方法导致我们的代码变得复杂和可读性差。当你实现复杂的操作来频繁的更新界面,使用这种方式变得更加糟糕。为了解决这个问题,Android1.5提供了一个公共类叫做AsyncTask,它简化了任务线程和主线程之间的通信。
        在Android1.0和1.1也可使用AsyncTask只不过它的名字为UserTask。
        AsyncTask的目的就是帮助你管理线程。我们之前的例子很容易被改写如下形式:
public void onClick(View v) {
new DownloadImageTask().execute("http://example.com/image.png");
} private class DownloadImageTask extends AsyncTask {
protected Bitmap doInBackground(String... urls) {
return loadImageFromNetwork(urls[0]);
} protected void onPostExecute(Bitmap result) {
mImageView.setImageBitmap(result);
}
}
AsyncTask通过它的子类才能使用。要记住,一个AsyncTask实例必须在主线程创建并且只能被执行一次。完全理解和使用这个类,你可以阅读AsyncTask文档。这里快速的说一下AsyncTask是怎么工作的:
1>可以通过泛型指定它的类型:参数,进度值,任务的结果值。
2>doInBackGround()方法自动在工作线程中只想能够。
3>onPreExecute(),onPostExecute(),onProgressUpdate()方法都在UI线程中执行。
4>doInBackground()方法返回的值被当作参数传递给onPostExecute()方法。
5>你能够在doInBackground()方法里任何时候调用publishProgress()方法在UI线程中去执行onProgressUpdate()方法。
除了官方文档,你可以阅读几个复杂的例子源代码如Shelves(ShelvesActivity.java和AddBookActivity.java)和Photostream(LoginActivity.java,PhotostreamActivity.java和ViewPhotoActivity.java)。我强烈建议阅读Shelves的源代码,看它在配置改变(configuration
changes)的时候是如何保存任务的(persist task),当Activity销毁的时候是怎样取消任务的。
不要管它是否使用AsyncTask,总之要记住单线程模型的两个原则(rule):不要阻塞(block)UI线程;确保Android UI toolkit 只能在UI线程中被访问(access)。
AsyncTask使得做这些事情变得更简单。

Android中轻松使用线程的更多相关文章

  1. Android中使用Thread线程与AsyncTask异步任务的区别

    最近和几个朋友交流Android开发中的网络下载问题时,谈到了用Thread开启下载线程时会产生的Bug,其实直接用子线程开启下载任务的确是很Low的做法,那么原因究竟如何,而比较高大上的做法是怎样? ...

  2. Android中进程与线程

    常说的主线程(UI线程)是什么? 当一个Android程序刚启动的时候,我们的android系统就会启动一个带有一个单一线程的linux进程.默认情况下,所有的组件比如Activity都运行在同样的一 ...

  3. Android中,子线程使用主线程中的组件出现问题的解决方法

    Android中,主线程中的组件,不能被子线程调用,否则就会出现异常. 这里所使用的方法就是利用Handler类中的Callback(),接受线程中的Message类发来的消息,然后把所要在线程中执行 ...

  4. Android中进程与线程及如何在子线程中操作UI线程

    1. Android进程 一个应用程序被启动时,系统默认创建执行一个叫做"main"的线程.这个线程也是你的应用与界面工具包(android.widget和android.view ...

  5. Android中轻松显示Gif图片

    android中现在没有直接显示gif的view,只能通过mediaplay来显示,且还常常不能正常显示出来,为此写了这个gifview,其用法和imageview一样使用方法:1-把GifView. ...

  6. 2017-11-29 由runnable说起Android中的子线程和主线程

    1.首先纠正一个观点,就是runnable运行在子线程中是错误的观念.runnable只是创建了一个执行任务的对象,但是它本身并不会创建一个新的子线程,Runable只是给你接口让你实现工作线程的工作 ...

  7. Android中使用异步线程更新UI视图的几种方法

    在Android中子线程是不能更新ui的. 所以我们要通过其他方式来动态改变ui视图, 1.runOnUiThreadactivity提供的一个轻量级更新ui的方法,在Fragment需要使用的时候要 ...

  8. android 中的 Handler 线程间通信

    一. 在MainActivity中为什么只是类似的写一行如下代码就可以使用handler了呢? Handler handler = new Handler() { @Override public v ...

  9. RxJava 以及 Android 中的通用线程解决方案、并发与线程安全

    关于RxJava如今是熟到发紫了,所以对于它底层的动作机制的了解是迫在眉睫了,费话不多说,直接开始. 这里还是以之前获取个人github仓库列表为例,用retrofit+rxjava,也是实际项目中用 ...

随机推荐

  1. smarty内置函数

      1.{append} 追加 2.{assign} 赋值 3.{block} 块 4.{call} 调用 5.{capture}捕获 6.{config_load}用来从配置文件中加载config变 ...

  2. LeetCode:比较含退格字符串【844】

    LeetCode:比较含退格字符串[844] 题目描述 给定 S 和 T 两个字符串,当它们分别被输入到空白的文本编辑器后,判断二者是否相等,并返回结果. # 代表退格字符. 示例 1: 输入:S = ...

  3. HihoCoder - 1339 Dice Possibility(概率dp)

    题意:求用N(1<=N<=100)个骰子掷出M(1<=M<=600)的概率 分析:直接求概率可能出现6^100次方,会爆精度.可以用一个数组dp[i][j]记录用i个骰子掷出j ...

  4. Spark机器学习3·推荐引擎(spark-shell)

    Spark机器学习 准备环境 jblashttps://gcc.gnu.org/wiki/GFortranBinaries#MacOS org.jblas:jblas:1.2.4-SNAPSHOT g ...

  5. rest_framework解析器组件源码流程

    rest_framework解析器组件源码流程 解析器顾名思义就是对请求体进行解析.为什么要有解析器?原因很简单,当后台和前端进行交互的时候数据类型不一定都是表单数据或者json,当然也有其他类型的数 ...

  6. 为JAXB和response设置编码,解决wechat4j中文乱码

    如果有哪一个做程序员的小伙伴说自己没有遇到中文乱码问题,我是不愿意相信的.今天在做微信订阅号的智能回复时,又一时迷乱的跳进了中文乱码这个火坑.刚解决问题时,都欢呼雀跃了,完全忘记了她曾经带给我的痛苦. ...

  7. ggplot2 specific command

    # By default, the same scales are used for all panels. You can allow # scales to vary across the pan ...

  8. Select the JavaScript graphing libraries you would like to compare

    Select the JavaScript graphing libraries you would like to compare:             Overview Summary Fus ...

  9. 搭建maven项目步骤

    整体项目结构如下: 第一步 第二步 第三步:删除src目录,只留pom文件 第四步: 第五步: 6 7 8 9 10 11 12

  10. Java集合Collection&Map

    Map<K,V>是键值对,K - 此映射所维护的键的类型,V - 映射值的类型.键值是一一对应的关系: Collection是只有键,底层也是由键值对,但是值的类型被隐藏起来. Colle ...