博客标题也不知道写什么好,只是最近有时候发现Handler,Loop,HandlerThread很容易混淆,所以做了简单的笔记处理:
第一种 : 大概的意思给出说明图:
上面图中的模型,就平时很常见的当需要更新UI时,通过Handler发送一个Message事件出去,但是Message事件的路径是先入了主线程的MessageQueue队列(一般是FIFO模式)中,
然后Looper就像一个永恒的发动机一样,不断的"循环"的去查询MessageQueue队列中是否有Message消息,如果查询存在,就会然其出队列来处理,由于这个消息队列是共用主线程中的(这句话非常重要)MessageQueue,所以它可以更新UI显示或者做一些其他的事情,主要还是更新UI较多(在主线程中).
第二种:下面这一种其实更具有普遍性
为什么说更具有普遍性,其实可以想一想Activity其实也相当于一个线程对象/或者封装了线程对象,我看了mMainThread等里面的消息循环,大致这么理解的.将理论很难理解,
比如说,开发者要向一个对象依次按顺序发送N个消息,第N-a个消息不能够在N-a-1个消息未执行完成就开始,即保证前面一个消息执行完成了,才能够执行下一个消息,平时开发中这样的情况很常见,但是要注意,如果我们在Activity中新建一个Thread线程,那就相当于独立于主线程之外,所以在这个线程中不能够处理更新UI等事情,但是却可以做很多其他逻辑处理,而且它不会影响主线程的,它只会在它自己的线程中按着顺序一个一个的执行.
第三种: 还有一个HandlerThread,看了很多样例,既然在Thread单词前面加上Handler,就和Handler扯上了关系,但是这个我自己还需要研究研究它正真的机制,只知道这个东西新建以后,让其start,开发者做一些更新UI或者其他事情,系统会安排在后台"慢慢"的帮开发者完成,即使事情里面加了延时也不用当心,他不会去阻塞主线程的.
下面给出一个测试程序验证一下:
<1> : 新建一个Android工程:
<2> : DurianMainActivity.java
package com.durian.handlerthread; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.HandlerThread; import android.os.Looper; import android.os.Message; import android.util.Log; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.TextView; import android.widget.Toast; public class DurianMainActivity extends Activity { private final static String TAG = "DurianMainActivity"; private TextView mTextView; private TextView mTextViewA; private TextView mTextViewB; private TextView mTextViewC; private Button mButton; private Button mButtonA; private Button mButtonB; private Button mButtonC; private HandlerThread mHandlerThread; private HandlerThread mHandlerThreadA; private Handler mUIHandler; private Handler mUIHandlerA = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); mNumCount++; mTextViewA.setText("mNumCount : " + mNumCount); } }; private Handler mUIHandlerB=new Handler(){ @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } mTextViewB.setText("Number : "+mNumber++); Log.i(TAG,"Number : "+mNumber); } }; private int mLooperNum=0; private class LooperThread extends Thread{ public Handler mLooperHandler; @Override public void run() { // TODO Auto-generated method stub super.run(); Looper.prepare(); mLooperHandler=new Handler(){ @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } Log.i(TAG,"mLooperNum : "+mLooperNum++); //here is not UI thread // mTextViewC.setText("mLooperNum : "+mLooperNum); } }; Looper.loop(); } } private LooperThread mLooperThread; private Handler mBackgroundHandler; private Handler mBackgroundHandlerA; private int mCount = 0; private int mNumCount = 0; private int mNumber=0; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.durian_main); mTextView = (TextView) findViewById(R.id.durianview); mTextView.setText("ui count : " + mCount); mTextViewA = (TextView) findViewById(R.id.durianaview); mTextViewB = (TextView) findViewById(R.id.durianbview); mTextViewC=(TextView)findViewById(R.id.duriancview); mLooperThread=new LooperThread(); mLooperThread.start(); mButtonC=(Button)findViewById(R.id.buttonC); mButtonC.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { // TODO Auto-generated method stub Message msg=new Message(); msg.what=1; mLooperThread.mLooperHandler.sendMessage(msg); } }); mButtonB=(Button)findViewById(R.id.buttonB); mButtonB.setOnClickListener(new OnClickListener(){ @Override public void onClick(View v) { // TODO Auto-generated method stub new Thread(){ @Override public void run() { // TODO Auto-generated method stub super.run(); Looper.prepare(); Message msg=new Message(); msg.what=100; mUIHandlerB.sendMessage(msg); Looper.loop(); } }.start(); } }); mButtonA = (Button) findViewById(R.id.buttonA); mButtonA.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub mBackgroundHandlerA.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub Message msg = new Message(); msg.what = 100; mUIHandlerA.sendMessage(msg); } }); } }); mButton = (Button) findViewById(R.id.button); mButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub mBackgroundHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub for (int i = 0; i < 1; i++) { mUIHandler.post(new Runnable() { @Override public void run() { // TODO Auto-generated method stub mCount++; try { Thread.sleep(500); } catch (InterruptedException e) { // TODO Auto-generated catch block e.printStackTrace(); } mTextView.setText("ui count : " + mCount); Log.i(TAG, "ui count : " + mCount); } }); } } }); } }); mHandlerThread = new HandlerThread("backgroun_thread_post"); mHandlerThread.start(); mHandlerThreadA = new HandlerThread("backgroun_thread_send"); mHandlerThreadA.start(); mBackgroundHandler = new Handler(mHandlerThread.getLooper()); mBackgroundHandlerA = new Handler(mHandlerThreadA.getLooper()); mUIHandler = new Handler(); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); mHandlerThread.getLooper().quit(); } }
durian_main.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".DurianMainActivity" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/durianview" android:text="@string/hello_world" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="start" android:id="@+id/button"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/durianaview" android:text="@string/hello_world" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="startA" android:id="@+id/buttonA"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/durianbview" android:text="@string/hello_world" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="startB" android:id="@+id/buttonB"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/duriancview" android:text="@string/hello_world" /> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="startC" android:id="@+id/buttonC"/> </LinearLayout>
程序很简答,运行点击对应的按钮,就可以测试上面的结论了.
另外看一下按钮StartB和StartC两个的区别,哪一个会产生并线操作的问题,哪个才是真正合理的.