Android UI线程和非UI线程

UI线程及Android的单线程模型原则

  当应用启动,系统会创建一个主线程(main thread)

  这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件(components from the Android UI toolkit (components from the android.widget and android.view packages))发生交互。

  所以main thread也叫UI thread也即UI线程

  系统不会为每个组件单独创建线程,在同一个进程里的UI组件都会在UI线程里实例化,系统对每一个组件的调用都从UI线程分发出去

  结果就是,响应系统回调的方法(比如响应用户动作的onKeyDown()和各种生命周期回调)永远都是在UI线程里运行。

  当App做一些比较重(intensive)的工作的时候,除非你合理地实现,否则单线程模型的performance会很poor。

  特别的是,如果所有的工作都在UI线程,做一些比较耗时的工作比如访问网络或者数据库查询,都会阻塞UI线程导致事件停止分发(包括绘制事件)。对于用户来说,应用看起来像是卡住了,更坏的情况是,如果UI线程blocked的时间太长(大约超过5秒),用户就会看到ANR(application not responding)的对话框。

  另外,Andoid UI toolkit并不是线程安全的,所以你不能从非UI线程来操纵UI组件。你必须把所有的UI操作放在UI线程里,所以Android的单线程模型有两条原则:

  1.不要阻塞UI线程。

  2.不要在UI线程之外访问Android UI toolkit(主要是这两个包中的组件:android.widget and android.view)。

使用Worker线程

  根据单线程模型的两条原则,首先,要保证应用的响应性,不能阻塞UI线程,所以当你的操作不是即时的那种(not instantaneous),你应该把他们放进单另的线程中(叫做background或者叫worker线程)。

  比如点击按钮后,下载一个图片然后在ImageView中展示:

public void onClick(View v) {    new Thread(new Runnable() {        public void run() {            Bitmap b = loadImageFromNetwork("http://example.com/image.png");            mImageView.setImageBitmap(b);        }    }).start();}

  这段代码用新的线程来处理网络操作,但是它违反了第二条原则:

  Do not access the Android UI toolkit from outside the UI thread.

  从非UI线程访问UI组件会导致未定义和不能预料的行为

  为了解决这个问题,Android提供了一些方法,从其他线程访问UI线程:

  • Activity.runOnUiThread(Runnable)
  • View.post(Runnable)
  • View.postDelayed(Runnable, long)

  比如,上面这段代码可以这么改:

public void onClick(View v) {    new Thread(new Runnable() {        public void run() {            final Bitmap bitmap = loadImageFromNetwork("http://example.com/image.png");            mImageView.post(new Runnable() {                public void run() {                    mImageView.setImageBitmap(bitmap);                }            });        }    }).start();}

  这么改之后就是线程安全的了。

  但是,当操作变得复杂的时候,这种代码会变得非常复杂,为了处理非UI线程和UI线程之间更加复杂的交互,可以考虑在worker线程中使用一个Handler,来处理UI线程中传来的消息。

  也可以继承这个类AsyncTask。

Communicating with the UI Thread

  只有在UI线程中的对象才能操作UI线程中的对象,为了将非UI线程中的数据传送到UI线程,可以使用一个Handler运行在UI线程中。

  Handler是Android framework中管理线程的部分,一个Handler对象负责接收消息然后处理消息。

  你可以为一个新的线程创建一个Handler,也可以创建一个Handler然后将它和已有线程连接。

  如果你将一个Handler和你的UI线程连接,处理消息的代码就将会在UI线程中执行。

  可以在你创建线程池的类的构造方法中实例化Handler的对象,然后用全局变量存储这个对象。

  要和UI线程连接,实例化Handler的时候应该使用Handler(Looper)这个构造方法。

  这个构造方法使用了一个Looper对象,这是Android系统中线程管理的framework的另一个部分。

  当你用一个特定的Looper实例来创建一个Handler时,这个Handler就运行在这个Looper的线程中。

  在Handler中,要覆写handleMessage()方法。Android系统会在Handler管理的相应线程收到新消息时调用这个方法

  一个特定线程的所有Handler对象都会收到同样的方法。(这是一个“一对多”的关系)。

参考资料

  官方Training: 与UI线程通信:

  http://developer.android.com/training/multiple-threads/communicate-ui.html

  Guides: Processes and Threads

  http://developer.android.com/guide/components/processes-and-threads.html

  类参考:

  http://developer.android.com/reference/android/os/Looper.html

  http://developer.android.com/reference/android/os/Handler.html

  http://developer.android.com/reference/android/os/HandlerThread.html

  博客:

  Android的线程使用来更新UI----Thread、Handler、Looper、TimerTask等:

  http://www.cnblogs.com/playing/archive/2011/03/24/1993583.html

更多相关文章

  1. android studio 编译的时候出现的错误和解决方法
  2. Android 禁止Edittext弹出系统软键盘 的几种方法
  3. Android 使用 第三方 Sweet Alert Dialog 的时候出现的报错解决
  4. Android Camera 方法分析
  5. Android EditText不显示光标的解决方法
  6. android杀进程方法
  7. EditText不显示光标的解决方法
  8. android ScrollView边界阴影方法
  9. 转:Android 发送短信的方法

随机推荐

  1. android中drawable显示到view上的过程
  2. 控件:拖动条 --- SeekBar(改变屏幕亮度)
  3. android 代码设置apn
  4. Android 通过代码执行Linux 命令 echo 命
  5. android的单个图片 上传服务器
  6. 网址收藏
  7. android 漂亮的listview
  8. 第四例:Intent启动Activity的几种方式(一)
  9. android中如何实现循环更新UI
  10. 一些在Android中的小设置~~~持续添加