Android UI线程和非UI线程

 

Android UI线程和非UI线程

 

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

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

  这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件(components from the Android UI toolkit (components from the android.widget andandroid.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 andandroid.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/p_w_picpath.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/p_w_picpath.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对象都会收到同样的方法。(这是一个“一对多”的关系)。


更多相关文章

  1. Android 系统音量最大值的定义位置以及默认值的修改方法
  2. Android AlertDialog的基本使用方法
  3. Android之设置横、竖屏方法
  4. Android获取本机Mac地址及IP地址方法

随机推荐

  1. Android界面设计学习日志(一)
  2. [hessdroid]Android下使用Hessian与Java
  3. Go 和 Android 集成实战
  4. android仿网易云音乐引导页、仿书旗小说F
  5. android windowManager
  6. 【Android 内存优化】Bitmap 内存缓存 (
  7. Android中Intent,service,broadcast应用浅
  8. Android漏洞挖掘工具收集与整理
  9. 范例解析:学习Android的IPC主板模式
  10. android 字节数据的转换与处理