美文网首页
Android UI线程和非UI线程

Android UI线程和非UI线程

作者: MrMagicWang | 来源:发表于2016-07-16 12:40 被阅读1012次

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线程中传来的消息。

相关文章

  • Android系列:彻底了解Handler

    一、Handler 1.1 Android为什么==非ui线程==不能==更新ui== UI线程的机制 为什么UI...

  • 关于Android在非UI线程更新UI的问题。

    为了解决在Android非UI线程更新UI这个问题,Android提供了一些方法,从其他线程访问UI线程。 Act...

  • 10.1 Android的消息机制概述

    Android规定访问UI只能在主线程中进行。ViewRootImp 对线程进行了校验,非UI线程操作UI会抛出异...

  • 理解JS 线程,和Android线程

    1,Android开发都知道,UI线程,和子线程; UI线程:可以操作ui界面, 子线程:不可以操作ui界面 2,...

  • Android 面试问题

    Android线程安全Android一般情况下会使用一个主线程控制UI,非主线程无法控制UI,Android4.0...

  • Android UI线程和非UI线程

    UI线程及Android的单线程模型原则 当应用启动,系统会创建一个主线程。这个主线程负责向UI组件分发事件(包括...

  • 浅析Android 消息机制

    消息机制存在的意义 为什么不能在非UI线程中操作UI控件?因为Android的UI控件不是线程安全的,如果在多线程...

  • Handler和AsyncTask知识学习

    在Android中不允许非UI线程直接对UI进行修改,否则会出错。UI线程就是主线程。Handler的出现就是为了...

  • 异步消息处理

    异步消息处理 android耗时操作只能放在非主线程,message从子线程进入主线程,从不能更新UI到更新UI,...

  • Android 进阶之 Handler 消息机制

    众所周知,在 Android 中,非 UI 线程中是不能更新 UI 的,如果在子线程中做 UI 相关操作,可能会出...

网友评论

      本文标题:Android UI线程和非UI线程

      本文链接:https://www.haomeiwen.com/subject/pncujttx.html