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

当应用启动,系统会创建一个主线程
  这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件发生交互。
  所以主线程也叫UI线程

系统不会为每个组件单独创建线程,在同一个进程里的UI组件都会在UI线程里实例化,系统对每一个组件的调用都是从UI线程分发出去的。结果就是,响应系统回调的方法永远都是在UI线程里进行的

当App在做一些比较繁重的操作的时候,比如网络请求、数据库操作等相关操作。如果这些工作都在UI线程里进行,就会阻塞UI线程,导致时间停止分发。对于用户来说,应用看起来就像卡住了,更坏的情况是,如果UI线程阻塞时间过长,用户就会看到应用无响应提示。

另外,Android UI toolkit并不是线程安全的,所以你不能从非UI线程来操作UI组件。必须把所有的UI操作放在UI线程里。

所以android单线程模型有两条原则
  1. 不要阻塞UI线程。
  2. 不要再UI线程外操作UI组件。

使用worker线程

根据单线程模型的两条原则,首先,要保证应用的响应性,不能阻塞UI线程,所以当你的操作十分耗时,你应该把他们放进另外的单独线程中(叫做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();}

这段代码用新的线程来处理网络操作,但是它违反了第二条原则:不能从非UI线程访问UI组件。

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

  • Activity.runOnUiThread(Runnable)
    这个函数是Activity的成员函数,它的源码为:
public final void runOnUiThread(Runnable action) {    if(Thread.currentThread() != mUiThread) {        mHandler.post(action);    } else {        action.run();    }}

利用Activity.runOnUiThread(Runnable)把更新ui的代码创建在Runnable中,然后在需要更新ui时,把这个Runnable对象传给Activity.runOnUiThread(Runnable)。 Runnable对像就能在ui程序中被调用。如果当前线程是UI线程,那么行动是立即执行。如果当前线程不是UI线程,操作是发布到事件队列的UI线程。

new Thread(new Runnable() {      @Override      public void run() {            runOnUiThread(new Runnable() {                @Override                public void run() {                    Toast.makeText(MainActivity.this, "hah", Toast.LENGTH_SHORT).show();                }             });       }}).start();
  • View.post(Runnable)

在post(Runnable action)方法里,View获得当前线程(即UI线程)的Handler,然后将action对象post到Handler里。在Handler里,它将传递过来的action对象包装成一个Message(Message的callback为action),然后将其投入UI线程的消息循环中。在Handler再次处理该Message时,有一条分支(未解释的那条)就是为它所设,直接调用runnable的run方法。而此时,已经路由到UI线程里,因此,我们可以毫无顾虑的来更新UI。

由于不是在新的线程中使用,所以千万别做复杂的计算逻辑。
                              参考自清沁

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();}
  • View.postDelayed(Runnable, long)

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

更多相关文章

  1. android启动第一个界面时即闪屏的核心代码(两种方式)
  2. React Native使用原生UI组件
  3. Android启动service下载失败后stopService,重新启动service下载出
  4. System.Lazy延迟加载 在很多情况下,有些对象需要在使用时加载或根
  5. Android用户界面 UI组件--TextView及其子类(四) Chronometer计时
  6. Android界面布局编程
  7. Android之Handler:实现计时器实例
  8. Android中线程同步
  9. 第27章、流动视图ScrollView(从零开始学Android)

随机推荐

  1. Android(安卓)ANR问题分析
  2. Android七大布局
  3. listview使用小技巧
  4. ROS与Android的通信
  5. java/android 统计文件夹大小及删除文件
  6. Android 登录界面Demo源码
  7. android在代码中为new出的控件设置ID及se
  8. EditText android:windowSoftInputMode
  9. Android EditText 为空提示 密码隐藏
  10. Android之SimpleAdapter简单实例和Simple