Android Handle消息机制:秒懂Looper、Handler、Message三者关系
1).Android 价值千万 java线程专题:Wait¬ify&join&Yield
http://blog.csdn.net/whb20081815/article/details/65627387
2).Android 价值千万 java多线程同步 <二>Callable和Future&FutureTask
http://blog.csdn.net/whb20081815/article/details/65630694
3).Android 价值千万 java多线程<三>生产者消费者模型四种实现方法
http://blog.csdn.net/whb20081815/article/details/65635647
4).Android 价值千万 java多线程同步 <四> synchronized&Lock&Atomic6种方式
http://blog.csdn.net/whb20081815/article/details/66971983
5).Android 价值千万java多线程同步 <五>CountDownLatch(计数器)和Semaphore(信号量)
http://blog.csdn.net/whb20081815/article/details/68498371
6).Android AsyncTask 那些你不知道的事
https://blog.csdn.net/WHB20081815/article/details/70332209
7).Android 厉害了ThreadLocal的工作原理和实例分析
https://blog.csdn.net/WHB20081815/article/details/66974651
8).Android Handle消息机制:秒懂Looper、Handler、Message三者关系
https://blog.csdn.net/WHB20081815/article/details/67639060
9).Android 性能优化<八> 多线程优化和线程管理
https://blog.csdn.net/WHB20081815/article/details/77775444
一般情况下,在主线程中我们绑定了Handler,并在事件触发上面创建新的线程用于完成某些耗时的操作,当子线程中的工作完成之后,会对Handler发送一个完成的信号,而Handler接收到信号后,就进行主UI界面的更新操作。
Handler机制主要为了解决以下2个问题
1. 不要阻塞UI线程;
2. 不要在UI线程之外访问UI组件,即不能在子线程访问UI组件,只能在UI线程访问。
1、Looper
对于Looper主要是prepare()和loop()两个方法。
首先看prepare()方法
private static void prepare(boolean quitAllowed) { if (sThreadLocal.get() != null) { throw new RuntimeException("Only one Looper may be created per thread"); } sThreadLocal.set(new Looper(quitAllowed));}
ThreadLocal保证了一个线程中只有一个Looper实例
在构造方法中,创建了一个MessageQueue(消息队列)。
private Looper(boolean quitAllowed) { mQueue = new MessageQueue(quitAllowed); mThread = Thread.currentThread();}
Loop方法:里面一个For循环,阻塞队列,不断的取消息
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; // Make sure the identity of this thread is that of the local process, // and keep track of what that identity token actually is. Binder.clearCallingIdentity(); final long ident = Binder.clearCallingIdentity(); for (;;) { Message msg = queue.next(); // might block if (msg == null) { // No message indicates that the message queue is quitting. return; }
Looper主要作用:
1、 与当前线程绑定,保证一个线程只会有一个Looper实例,同时一个Looper实例也只有一个MessageQueue。
2、 loop()方法,不断从MessageQueue中去取消息,交给消息的target属性的dispatchMessage去处理。
好了,我们的异步消息处理线程已经有了消息队列(MessageQueue),也有了在无限循环体中取出消息的哥们,现在缺的就是发送消息的对象了,于是: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;}
发送消息:把消息添加到了MessageQueue队列里面
移除消息:通过MessageQueue
public final void removeMessages(int what) { mQueue.removeMessages(this, what, null);}
总结流程:
1、首先Looper.prepare()在本线程中保存一个Looper实例,然后该实例中保存一个MessageQueue对象;因为Looper.prepare()在一个线程中只能调用一次,所以MessageQueue在一个线程中只会存在一个。
2、Looper.loop()会让当前线程进入一个无限循环,不端从MessageQueue的实例中读取消息,然后回调msg.target.dispatchMessage(msg)方法。
3、Handler的构造方法,会首先得到当前线程中保存的Looper实例,进而与Looper实例中的MessageQueue想关联。
4、Handler的sendMessage方法,会给msg的target赋值为handler自身,然后加入MessageQueue中。
5.报错Can't create handler inside thread that has not called Looper.prepare(),没有调用Looper.loop().UI线程默认调用了Looper.prepare()和Looper.loop()方法。Looper.prepare()和Looper.loop()方法。
列子:
public void testHandler2(final TextView textView){ mHandler=new Handler(); new Thread(new Runnable() { @Override public void run() { while (true){ i++; mHandler.post(new Runnable() { @Override public void run() { textView.setText(""+i); Log.d("mHandler",""+i); } }); try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } } }).start();}
错误代码如下:
/** * Error,while死循环,主线程做了耗时的操作 * @param textView */ public void testHandler(final TextView textView){ mHandler=new Handler(getMainLooper()); mHandler.post(new Runnable() { @Override public void run() {// textView.setText(""+i); while (true){ Log.d("mHandler",""+i+"ThreadName"+Thread.currentThread().getName()); i++; if(i%1000==0){ textView.setText(""+i); } } } }); }
AS代码地址:不知道为什么上传不了
更多相关文章
- 【Android M】Monkey命令源码及是否处于monkey测试的判断方法
- Bugly Android 这个错误 Cleartext HTTP traffic to android.bug
- Android应用程序消息处理机制(Looper、Handler)源码分析
- FregServer进程,启动Binder线程池,睡眠等待在proc->wait
- Android中,把XML文件转换成Object对象的方法
- Android 死机问题分析方法收集
- android]Android 线程优先级修改
- Android中通过资源文件获取drawable的几种方法