(转)收集——Android Handler分析总结篇

来源:互联网 发布:mac 显示已经更新系统 编辑:程序博客网 时间:2024/06/01 10:05

    • Handler
      • Handler的由来
      • handler的作用
        • 让线程延时执行
        • 让任务在其他线程中执行并返回结果
      • Handler原理分析
        • Handler的构造函数
        • Handle发送消息的几个方法源码
    • Looper原理分析
      • 首先看prepare方法
      • loop方法
      • quit
      • Handler的dispatchMessage的源码如下
    • Looper_handler_thread_message
      • 定义
      • 关系
      • 线程的魔法师 Looper
      • MessageQueue
      • Message
      • Handler
    • 如何在子线程中使用Handler
    • Android Handler内存泄露分析
      • 切断handler和msg的联系
      • 切断handler和外部类的引用
    • 子线程更新UI的几种方式
      • Viewpost
      • runOnUiThread
      • 不使用Handler真的不能更新UI吗研究但不推荐
    • 总结
    • 参考链接

Handler

Handler的由来

当程序第一次启动的时候,Android会同时启动一条主线程( Main Thread)来负责处理与UI相关的事件,我们叫做UI线程。

 Android的UI操作并不是线程安全的(出于性能优化考虑),意味着如果多个线程并发操作UI线程,可能导致线程安全问题。

  为了解决Android应用多线程问题—Android平台只允许UI线程修改Activity里的UI组建,就会导致新启动的线程无法改变界面组建的属性值。

  简单的说:当主线程队列处理一个消息超过5秒,android 就会抛出一个 ANR(无响应)的异常,所以,我们需要把一些要处理比较长的消息,放在一个单独线程里面处理,把处理以后的结果,返回给主线程运行,就需要用的Handler来进行线程建的通信。

handler的作用

让线程延时执行

两个主要方法:

final boolean postAtTime(Runnable r, long uptimeMillis)final boolean postDelayed(Runnable r, long delayMillis)

让任务在其他线程中执行并返回结果

分为两个步骤:

在新启动的线程中发送消息

  使用Handler对象的sendMessage()方法或者SendEmptyMessage()方法发送消息。

在主线程中获取处理消息

  重写Handler类中处理消息的方法(void handleMessage(Message msg)),当新启动的线程发送消息时,消息发送到与之关联的MessageQueue。而Hanlder不断地从MessageQueue中获取并处理消息。

Handler原理分析

Handler的构造函数

public Handler() public Handler(Callbackcallback) public Handler(Looperlooper) public Handler(Looperlooper, Callbackcallback)  

(1)第①个和第②个构造函数都没有传递Looper,这两个构造函数都将通过调用Looper.myLooper()获取当前线程绑定的Looper对象,然后将该Looper对象保存到名为mLooper的成员字段中。

下面来看①②个函数源码:

public Handler() {    this(null, false);}public Handler(Callback callback) {     this(callback, false);}//他们会调用Handler的内部构造方法public Handler(Callback callback, boolean async) {    if (FIND_POTENTIAL_LEAKS) {        final Class<? extends Handler> klass = getClass();        if ((klass.isAnonymousClass() ||klass.isMemberClass()         || klass.isLocalClass()) &&            (klass.getModifiers() & Modifier.STATIC) == 0) {                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +                klass.getCanonicalName());            }        }/************************************    mLooper = Looper.myLooper();    if (mLooper == null) {        throw new RuntimeException(            "Can't create handler inside thread that has not called Looper.prepare()");    }    mQueue = mLooper.mQueue;    mCallback = callback;    mAsynchronous = async;}

通过Looper.myLooper()获取了当前线程保存的Looper实例,又通过这个Looper实例获取了其中保存的MessageQueue(消息队列)。每个Handler 对应一个Looper对象,产生一个MessageQueue 。

(2)第③个和第④个构造函数传递了Looper对象,这两个构造函数会将该Looper保存到名为mLooper的成员字段中。
下面来看③④个函数源码:

public Handler(Looper looper) {    this(looper, null, false);} public Handler(Looper looper, Callback callback) {    this(looper, callback, false);}//他们会调用Handler的内部构造方法public Handler(Looper looper, Callback callback, boolean async) {    mLooper = looper;    mQueue = looper.mQueue;    mCallback = callback;    mAsynchronous = async;}

(3)第②个和第④个构造函数还传递了Callback对象,Callback是Handler中的内部接口,需要实现其内部的handleMessage方法,Callback代码如下:

 public interface Callback {     public boolean More ...handleMessage(Message msg);}

Handler.Callback是用来处理Message的一种手段,如果没有传递该参数,那么就应该重写Handler的handleMessage方法,也就是说为了使得Handler能够处理Message,我们有两种办法:
  
 1. 向Hanlder的构造函数传入一个Handler.Callback对象,并实现Handler.Callback的handleMessage方法  
  
 2. 无需向Hanlder的构造函数传入Handler.Callback对象,但是需要重写Handler本身的handleMessage方法  
   
   也就是说无论哪种方式,我们都得通过某种方式实现handleMessage方法,这点与Java中对Thread的设计有异曲同工之处。

Handle发送消息的几个方法源码

这里写图片描述

 public final boolean sendMessage(Message msg)    {        return sendMessageDelayed(msg, 0);    }   public final boolean sendEmptyMessageDelayed(int what, long delayMillis) {        Message msg = Message.obtain();        msg.what = what;        return sendMessageDelayed(msg, delayMillis);    } public final boolean sendMessageDelayed(Message msg, long delayMillis)    {        if (delayMillis < 0) {            delayMillis = 0;        }        return sendMessageAtTime(msg, SystemClock.uptimeMillis() + delayMillis);    } public boolean sendMessageAtTime(Message msg, long uptimeMillis) {        MessageQueue queue = mQueue;        if (queue == null) {            RuntimeException e = new RuntimeException(                    this + " sendMessageAtTime() called with no mQueue");            Log.w("Looper", e.getMessage(), e);            return false;        }        return enqueueMessage(queue, msg, uptimeMillis);    }

可以看出他们最后都调用了sendMessageAtTime(),然后返回了enqueueMessage方法,下面看一下此方法源码:

private boolean enqueueMessage(MessageQueue queue, Message msg, long uptimeMillis) {  //把当前的handler作为msg的target属性    msg.target = this;    if (mAsynchronous) {          msg.setAsynchronous(true);    }    return queue.enqueueMessage(msg, uptimeMillis);}

queue.enqueueMessage :
变量queue表示的是Handler所绑定的消息队列MessageQueue,通过调用queue.enqueueMessage(msg, uptimeMillis)我们将Message放入到消息队列中。
这里写图片描述

Looper原理分析

我们一般在主线程申明Handler,有时我们需要继承Thread类实现自己的线程功能,当我们在里面申明Handler的时候会报错。其原因是主线程中已经实现了两个重要的Looper方法,下面看一看ActivityThread.java中main方法的源码:

public static void main(String[] args) {    //......省略    Looper.prepareMainLooper();//>    ActivityThread thread = new ActivityThread();    thread.attach(false);    if (sMainThreadHandler == null) {        sMainThreadHandler = thread.getHandler();    }    AsyncTask.init();    if (false) {        Looper.myLooper().setMessageLogging(new            LogPrinter(Log.DEBUG, "ActivityThread"));    }    Looper.loop();//>    throw new RuntimeException("Main thread loop unexpectedly exited");}

首先看prepare()方法

public static void prepare() {     prepare(true);}private static void prepare(boolean quitAllowed) {   //证了一个线程中只有一个Looper实例    if (sThreadLocal.get() != null) {         throw new RuntimeException("Only one Looper may be created per thread");    }    sThreadLocal.set(new Looper(quitAllowed));}

该方法会调用Looper构造函数同时实例化出MessageQueue和当前thread.

private Looper(boolean quitAllowed) {    mQueue = new MessageQueue(quitAllowed);    mThread = Thread.currentThread();} public static MessageQueue myQueue() {    return myLooper().mQueue;}

prepare()方法中通过ThreadLocal对象实现Looper实例与线程的绑定。

loop()方法

public static void loop() {    final Looper me = myLooper();    if (me == null) {         throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");    }    final MessageQueue queue = me.mQueue;    Binder.clearCallingIdentity();    final long ident = Binder.clearCallingIdentity();    for (;;) {        Message msg = queue.next(); // might block        if (msg == null) {            return;        }        Printer logging = me.mLogging;        if (logging != null) {            logging.println(">>>>> Dispatching to " + msg.target + " " +                    msg.callback + ": " + msg.what);        }//重点****        msg.target.dispatchMessage(msg);        if (logging != null) {            logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);        }        // identity of the thread wasn't corrupted.        final long newIdent = Binder.clearCallingIdentity();        if (ident != newIdent) {            Log.wtf(TAG, "Thread identity changed from 0x"                    + Long.toHexString(ident) + " to 0x"                    + Long.toHexString(newIdent) + " while dispatching to "                    + msg.target.getClass().getName() + " "                    + msg.callback + " what=" + msg.what);        }        msg.recycleUnchecked();    }}

首先looper对象不能为空,就是说loop()方法调用必须在prepare()方法的后面。
Looper一直在不断的从消息队列中通过MessageQueue的next方法获取Message,然后通过代码msg.target.dispatchMessage(msg)让该msg所绑定的Handler(Message.target)执行dispatchMessage方法以实现对Message的处理。

:写在Looper.loop()之后的代码不会被立即执行,当调用后 mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。Looper对象通过MessageQueue 来存放消息和事件。一个线程只能有一个Looper,对应一个MessageQueue。

quit()

public void quit() {     Message msg = Message.obtain();     // NOTE: By enqueueing directly into the message queue, the     // message is left with a null target.  This is how we know it is     // a quit message.     mQueue.enqueueMessage(msg, 0);}

Handler的dispatchMessage的源码如下:

public void dispatchMessage(Message msg) {     if (msg.callback != null) {         handleCallback(msg);     } else {         if (mCallback != null) {             if (mCallback.handleMessage(msg)) {                 return;            }        }        handleMessage(msg);    }}

可以看到Handler提供了三种途径处理Message,而且处理有前后优先级之分:首先尝试让postXXX中传递的Runnable执行,其次尝试让Handler构造函数中传入的Callback的handleMessage方法处理,最后才是让Handler自身的handleMessage方法处理Message。

Looper_handler_thread_message

定义

Message:消息,其中包含了消息ID,消息处理对象以及处理的数据等,由MessageQueue统一列队,终由Handler处理。

Handler:处理者,负责Message的发送及处理。使用Handler时,需要实现handleMessage(Message msg)方法来对特定的Message进行处理,例如更新UI等。

MessageQueue:消息队列,用来存放Handler发送过来的消息,并按照FIFO规则执行。当然,存放Message并非实际意义的保存,而是将Message以链表的方式串联起来的,等待Looper的抽取。

Looper:消息泵,不断地从MessageQueue中抽取Message执行。因此,一个MessageQueue需要一个Looper。

Thread:线程,负责调度整个消息循环,即消息循环的执行场所。

Android 系统的消息队列和消息循环都是针对具体线程的,一个线程可以存在(当然也可以不存在)一个消息队列和一个消息循环(Looper),特定线程的消息只能分发给本线程,不能进行跨线程,跨进程通讯。但是创建的工作线程默认是没有消息循环和消息队列的,如果想让该线程具有消息队列和消息循环,需要在线程中首先调用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环。

关系

这里写图片描述
Handler,Looper和MessageQueue就是简单的三角关系。Looper和MessageQueue一一对应,创建一个Looper的同时,会创建一个MessageQueue。Message Queue(消息队列),MQ被封装到Looper里面了,我们不会直接与MQ打交道。而Handler与它们的关系,只是简单的聚集关系,即Handler里会引用当前线程里的特定Looper和MessageQueue。

这样说来,多个Handler都可以共享同一Looper和MessageQueue了。当然,这些Handler也就运行在同一个线程里。

线程的魔法师 Looper

是MessageQueue的管理者。每一个MessageQueue都不能脱离Looper而存在,Looper对象的创建是通过prepare函数来实现的。同时每一个Looper对象和一个线程关联。通过调用Looper.myLooper()可以获得当前线程的Looper对象创建一个Looper对象时,会同时创建一个MessageQueue对象。除了主线程有默认的Looper,其他线程默认是没有MessageQueue对象的,所以,不能接受Message。如需要接受,自己定义 一个Looper对象(通过prepare函数),这样该线程就有了自己的Looper对象和MessageQueue数据结构了。Looper从MessageQueue中取出Message然后,交由Handler的handleMessage进行处理。处理完成后,调用Message.recycle()将其放入Message Pool中。

Looper的字面意思是“循环者”,它被设计用来使一个普通线程变成Looper线程。所谓Looper线程就是循环工作的线程。在程序开发中(尤其是GUI开发中),我们经常会需要一个线程不断循环,一旦有新任务则执行,执行完继续等待下一个任务,这就是Looper线程。使用Looper类创建Looper线程很简单:

public class LooperThread extends Thread {    @Override    public void run() {        // 将当前线程初始化为Looper线程        Looper.prepare();        // ...其他处理,如实例化handler        // 开始循环处理消息队列        Looper.loop();    }}

通过上面两行核心代码,你的线程就升级为Looper线程了!!!

MessageQueue

是一种 数据 结构,见名知义,就是一个消息队列,存放消息的地方。每一个线程最多只可以拥有一个MessageQueue数据结构。创建一个线程的时候,并不会自动 创建其MessageQueue。通常使用一个Looper对象对该线程的MessageQueue进行管理。主线程创建时,会创建一个默认的Looper对象,而Looper对象的创建,将自动创建一个Message Queue。其他非主线程,不会自动创建Looper,要需要的时候,通过调用prepare函数来实现。

Message:

消息对象,Message Queue中的存放的对象。一个Message Queue中包含多个Message。 Message实例对象的取得,通常使用Message类里的静态方法obtain(),该方法有多个重载版本可供选择;它的创建并不一定是直接创建一个新的实例,而是先从Message Pool(消息池)中看有没有可用的Message实例,存在则直接取出返回这个实例。如果Message Pool中没有可用的Message实例,则才用给定的参数创建一个Message对象。调用removeMessages()时,将Message从Message Queue中删除,同时放入到Message Pool中。除了上面这种方式,也可以通过Handler对象的obtainMessage()获取 一个Message实例。

Handler

消息的处理者,handler 负责将需要传递的信息封装成Message,通过调用handler 对象的obtainMessage()来实现;将消息传递给Looper,这是通过handler 对象的sendMessage()来实现的。继而由Looper将Message放入MessageQueue中。当Looper对象看到MessageQueue中含有Message,就将其广播出去。该handler 对象收到该消息后,调用相应的handler 对象的handleMessage()方法对其进行处理。

如何在子线程中使用Handler

Handler本质是从当前的线程中获取到Looper来监听和操作MessageQueue,当其他线程执行完成后回调当前线程。
子线程需要先prepare()才能获取到Looper的,是因为在子线程只是一个普通的线程,其ThreadLoacl中没有设置过Looper,所以会抛出异常,而在Looper的prepare()方法中sThreadLocal.set(new Looper())是设置了Looper的。

class Rub implements Runnable {          public Handler myHandler;          // 实现Runnable接口的线程体         @Override          public void run() {           /*①、调用Looper的prepare()方法为当前线程创建Looper对象并,          创建Looper对象时,它的构造器会自动的创建相对应的MessageQueue*/            Looper.prepare();              /*.②、创建Handler子类的实例,重写HandleMessage()方法,该方法处理除当前线程以外线程的消息*/             myHandler = new Handler() {                  @Override                  public void handleMessage(Message msg) {                      String ms = "";                      if (msg.what == 0x777) {                      }                  }              };              //③、调用Looper的loop()方法来启动Looper让消息队列转动起来            Looper.loop();          }    }

注意分成三步: 

1.调用Looper的prepare()方法为当前线程创建Looper对象,创建Looper对象时,它的构造器会创建与之配套的MessageQueue。  

2.有了Looper之后,创建Handler子类实例,重写HanderMessage()方法,该方法负责处理来自于其他线程的消息。  

3.调用Looper的looper()方法启动Looper。

  然后使用这个handler实例在任何其他线程中发送消息,最终处理消息的代码都会在你创建Handler实例的线程中运行。
更好一点的示例参考:

public class MainActivity extends Activity {      private LooperThread  looperThread;      @Override      public void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.main_layout);          looperThread = new LooperThread();          looperThread.start();      looperThread.getHandler().sendEmptyMessage(1);      }      class LooperThread extends Thread {          private Handler mHandler;          private final Object mLock = new Object();          public void run() {              Looper.prepare();              synchronized (mLock) {                  mHandler = new Handler(){                      @Override                      public void handleMessage(Message msg) {                          .....                      }                  };                  mLock.notifyAll();              }              Looper.loop();          }          public Handler getHandler() {              synchronized (mLock) {                  if (mHandler == null) {                      try {                          mLock.wait();                      } catch (InterruptedException e) {                      }                  }                  return mHandler;              }          }          public void exit() {              getHandler().post(new Runnable(){                  public void run() {                      Looper.myLooper().quit();                  }});          }      }  } 

Android Handler内存泄露分析

This Handler class should be static or leaks might occur。

这个警告的产生是由于将Handler声明为了非静态内部类(匿名或非匿名),这种情况下可能会产生内存泄露,导致Activity无法释放。

我们使用Handler post一个Message时,Message会在主线程的MessageQueue中排队。由于消息处理中需要调用Message对应Handler的回调,Message会持有Handler的引用。当Handler为非静态内部类(匿名或非匿名)时,Handler就会持有外部类的引用,如果外部类是Activity,这个Activity对象有可能会泄露,尤其是通过调用Handler的postDelayed()方法发送消息,Message会长时间在MessageQueue中存在,泄露的可能性将更大。

要解决这个问题,需要做的就是想办法切断这个引用关系链(Message -> Handler -> Activity),要么切断Message -> Handler的引用,要么切断Handler -> Activity的引用。

切断handler和msg的联系

处理方法是在使用Handler的组件生命周期结束前清除掉MessageQueue中的Message对象(比如,在Activity的onDestroy()中调用Handler的remove*方法)。Handler主要有下面一些方法来清楚Message对象:
比如:handler启动runnable,延迟启动作用等。

private Handler handler = new Handler();private Runnable runnable = new Runnable(){       public void run(){               update();               handler.postDelayed(runnable.this,1000);       }};handler.postDelayed(runnable,1000); //开始timerhandler.removeCallbacks(runnable);  //停止Timerps:当然runnable也可以用Implements的方式.
removeCallbacks(Runnable r) ——清除r匹配上的Message。removeCallbacks(Runnable r, Object token) ——清除r匹配且匹配token(Message.obj)的Message,token为空时,只匹配r。removeCallbacksAndMessages(Object token) ——清除token匹配上的Message。removeMessages(int what) ——按what来匹配removeMessages(int what, Object object) ——按what来匹配我们需要的是清除以该Handler为target的所有Message(包括Callback),那么调用如下方法即可handler.removeCallbacksAndMessages(null);

切断handler和外部类的引用

可以将Handler声明为静态内部类,避免对外部类的强引用,如果在Handler的内部方法中需要引用外部类,可以在其内部声明一个WeakReference引用外部类的实例。

public class MyActivity extends Activity{      MyHandler myHandler = new MyHandler(this);      @Override      protected void onCreate(Bundle savedInstanceState) {          super.onCreate(savedInstanceState);          setContentView(R.layout.activity_main);      }      @Override      protected void onDestroy() {          super.onDestroy();          myHandler.removeCallbacksAndMessages(null);      }      private static class MyHandler extends Handler{          private WeakReference<MyActivity> activity;          MyHandler(MyActivity ac) {              activity = new WeakReference<MyActivity>(ac);          }          @Override          public void handleMessage(Message msg) {              super.handleMessage(msg);              //do something              if (activity != null) {                  MyActivity myActivity = activity.get();                  //......              }          }      };  }  

子线程更新UI的几种方式

Handler.post(Runnable)Handler.sendMessage()View.post(Runnable)AsyncTaskActivity.runOnUiThread()

这几种方式看起来差别很大,但实际上它们的原理都是相同的,最终都是通过Handler的sendMessage方法来发送消息,然后在UI线程中处理Handler的回调。只是Google帮我们对Handler机制进行了不同程度的封装以适应不同的应用场景。

View.post()

public boolean post(Runnable action) {      final AttachInfo attachInfo = mAttachInfo;      if (attachInfo != null) {          return attachInfo.mHandler.post(action);      }      // Assume that post will succeed later      ViewRootImpl.getRunQueue().post(action);      return true;  }  

方法中调用了attachInfo.mHandler.post(action)去发送消息,其实就是调用了Handler的post()方法,继续看这个方法:

public final boolean post(Runnable r)  {     return  sendMessageDelayed(getPostMessage(r), 0);  }  

post方法里使用的就是sendMessge()的方式发送消息。

runOnUiThread()

public final void runOnUiThread(Runnable action) {      if (Thread.currentThread() != mUiThread) {          mHandler.post(action);      } else {          action.run();      }  }  

首先判断是否是主线程,如果是就直接执行代码逻辑,如果不是,依然是调用了Handler 的post()方法。从这里可以看出,所有可以实现子线程更新UI的方法的原理都是一样的。

不使用Handler真的不能更新UI吗?(研究,但不推荐)

new Thread(new Runnable() {       @Override       public void run() {           btn.setText("aaaaaaaaa");       }   }).start();   new Thread(new Runnable() {       @Override       public void run() {           try {               Thread.sleep(5000);           } catch (InterruptedException e) {               e.printStackTrace();           }           btn.setText("cccccccc");       }   }).start();  

这段代码在Activity的onCreate回调中执行,btn是我们定义的一个Button对象。从执行结果看,第一段代码顺利执行且UI正确更新,却在执行第二段代码的时候发生了崩溃,这是为什么呢?

异常: Only the original thread that created a view hierarchy can touch its views.  

根据堆栈信息,更新UI时会调用View的invalidate()方法,继而调用ViewRootImpl的invalidateChildInParent()方法,其中调用了checkThread(),其中会检查当前是否为主线程,否则抛出上面的那个异常。

public ViewParent invalidateChildInParent(int[] location, Rect dirty) {          checkThread();          if (DEBUG_DRAW) Log.v(TAG, "Invalidate child: " + dirty);          if (dirty == null) {              invalidate();              return null;          } else if (dirty.isEmpty() && !mIsAnimating) {              return null;          }......}  
void checkThread() {      if (mThread != Thread.currentThread()) {          throw new CalledFromWrongThreadException(                  "Only the original thread that created a view hierarchy can touch its views.");      }  }  

也就是说是在ViewRootImpl这个类中进行了线程的检查。只是在onCreate()中更新UI的时候,ViewRootImpl的对象还没有创建,因此不会进行这个检查,也就出现了上面例子中的现象。那么它是在什么时候创建的呢?

ActivityThread类会调用handleResumeActivity方法将顶层视图DecorView添加到PhoneWindow中,我们就从handleResumeActivity开始看起。

final void handleResumeActivity(IBinder token, boolean clearHide, boolean isForward, boolean reallyResume) {              ..................              if (r.window == null && !a.mFinished && willBeVisible) {                  r.window = r.activity.getWindow();                  View decor = r.window.getDecorView();                  decor.setVisibility(View.INVISIBLE);                  //得当当前Activity的WindowManagerImpl对象                  ViewManager wm = a.getWindowManager();                  WindowManager.LayoutParams l = r.window.getAttributes();                  a.mDecor = decor;                  l.type = WindowManager.LayoutParams.TYPE_BASE_APPLICATION;                  l.softInputMode |= forwardBit;                  if (a.mVisibleFromClient) {                      a.mWindowAdded = true;                      wm.addView(decor, l);              .....................  

代码中,ViewManager wm = a.getWindowManager()这个得到的是一个WindowManagerImpl类的对象,然后调用了WindowManagerImpl类的addView方法。查看addView方法,又调用了mGlobal的addView方法,mGlobal是WindowManagerGlobal类的对象。

@Override  public void addView(View view, ViewGroup.LayoutParams params) {      mGlobal.addView(view, params, mDisplay, mParentWindow);  }  

然后看WindowManagerGlobal类的addView方法:

public void addView(View view, ViewGroup.LayoutParams params,              Display display, Window parentWindow) {          ............          ViewRootImpl root;          ............           root = new ViewRootImpl(view.getContext(), display);          ...........          // do this last because it fires off messages to start doing things          try {              root.setView(view, wparams, panelParentView);          } catch (RuntimeException e) {            ...........          }      }

终于看到了ViewRootImpl,它正式在这里创建的。也就是说,ViewRootImpl是在onResume执行之后创建的。这也就解释了为什么直接在Activity的onCreate中在子线程更新UI不会报错,而在延时一段时间后却出现崩溃。

总结

主线程中,系统已经初始化了一个Looper对象,因此可以直接创建Handler即可,就可以通过Handler来发送消息、处理消息。 程序自己启动的子线程,程序必须自己创建一个Looper对象,并启动它,调用Looper.prepare()方法。

prapare()方法:保证每个线程最多只有一个Looper对象。(因为初始创建第一个Looper的时候会设置成ThreadLocal,然后后面要是再次创建会判断,抛出异常)。

looper()方法:启动Looper,使用一个死循环不断取出MessageQueue中的消息,并将取出的消息分给对应的Handler进行处理。  

MessageQueue:由Looper负责管理,它采用先进先出的方式来管理Message。 

Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。 
  
Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。

参考链接

http://www.cnblogs.com/codingmyworld/archive/2011/09/14/2174255.html
http://blog.sina.com.cn/s/blog_5da93c8f0100y4ul.html
http://blog.csdn.net/amazing7/article/details/51424038
http://blog.csdn.net/goodlixueyong/article/details/50831958

0 0
原创粉丝点击