Android系统中的视图组件并不是线程安全的,如果要更新视图,必须在主线程中更新,不可以在子线程中执行更新的操作。(子线程一般肩负起比较繁重的任务),所以引入了Handler和AsyncTask机制。
Handler机制
public class NewThread3 extends Activity { public static final int UZI=0; private Button btn; private TextView text1; private Handler handler=new Handler(){ public void handleMessage(Message msg) { if(msg.what==UZI){ text1.setText("finally"); } }; }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); text1 = (TextView) findViewById(R.id.text1); btn = (Button) findViewById(R.id.btn1); btn.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { // TODO Auto-generated method stub new MyThread().start(); } }); } private class MyThread extends Thread { @Override public void run() { // TODO Auto-generated method stub super.run(); //处理比较耗时的操作 Message msg=new Message(); msg.what=UZI; handler.handleMessage(msg); } }}
子线程处理繁重的任务,然后通过Handler传送Message通知主线程更新ui,主线程拿到message后再处理并更新ui。
Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。
Android系统中的Looper负责管理线程的消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。
,一个线程可以存在一个消息队列和消息循环,特定线程的消息只能分发给本线程,不能跨线程和跨进程通讯。但是创建的工作线程默认是没有消息队列和消息循环的 所以需要用Looper.prepare()来创建消息队列,然后调用Looper.loop()进入消息循环 创建工作线程如下:class MyThread extends Thread { public Handler mHandler; public void run() { Looper.prepare(); mHandler = new Handler() { public void handleMessage(Message msg) { // 处理收到的消息 } }; Looper.loop(); } }
此时工作线程也有自己的消息处理机制了;
***Ui线程,也就是主线程,系统会默认分配消息队列和消息循环 了解了上面Handler和loop的关系后,再来看一个Ui线程和工作线程间进行消息传递的例子。public class MainActivity extends ActionBarActivity { private int mCount = 0; private Handler mHandlerThr = null; private Handler mHandler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.d(null, ">>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what="+msg.what); //接收发送到UI线程的消息,然后向线程中的Handler发送msg 1。 mHandlerThr.sendEmptyMessage(1); mCount++; if (mCount >= 3) { //由于mHandlerThr是在Child Thread创建,Looper手动死循环阻塞,所以需要quit。 mHandlerThr.getLooper().quit(); } } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); } @Override protected void onStop() { super.onStop(); //删除所有call与msg mHandler.removeCallbacksAndMessages(null); } private void initData() { Log.d(null, ">>>>>>>>>>>>>UI# begin start thread!!!"); new Thread() { @Override public void run() { super.run(); Looper.prepare(); mHandlerThr = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); Log.d(null, ">>>>>>>>>>>>>Child# mHandlerThr--handleMessage--msg.what=" + msg.what); //接收发送到子线程的消息,然后向UI线程中的Handler发送msg 0。 mHandler.sendEmptyMessage(0); } }; Log.d(null, ">>>>>>>>>>>>>Child# begin start send msg!!!"); //Activity中启动Thread,在Thread结束前发送msg 0到UI Thread。 mHandler.sendEmptyMessage(0); Looper.loop(); //不能在这个后面添加代码,程序是无法运行到这行之后的。 } }.start(); }}
运行结果如下:
>>>>>>>>>>>>>UI# begin start thread!!!>>>>>>>>>>>>>Child# begin start send msg!!!>>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what=0>>>>>>>>>>>>>Child# mHandlerThr--handleMessage--msg.what=1>>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what=0>>>>>>>>>>>>>Child# mHandlerThr--handleMessage--msg.what=1>>>>>>>>>>>>>UI# mHandler--handleMessage--msg.what=0
Handler与Looper实例化总结
在主线程中可以直接创建Handler对象,而在子线程中需要先调用Looper.prepare()才能创建Handler对象,否则运行抛出”Can’t create handler inside thread that has not called Looper.prepare()”异常信息。每个线程中最多只能有一个Looper对象,否则抛出异常。可以通过Looper.myLooper()获取当前线程的Looper实例,通过Looper.getMainLooper()获取主(UI)线程的Looper实例。一个Looper只能对应了一个MessageQueue。一个线程中只有一个Looper实例,一个MessageQueue实例,可以有多个Handler实例。
继续看看Handler消息收发机制源码
通过Handler发消息到消息队列
比较sendMessageAtTime()和sendMessageAtFrontOfQueue()方法
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); }
再看看sendMessageAtFrontOfQueue()方法
public final boolean sendMessageAtFrontOfQueue(Message msg) { 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, 0); }
Handler发送消息实质就是把消息Message添加到MessageQueue消息队列中的过程而已。
既然消息都存入到了MessageQueue消息队列,当然要取出来消息吧,不然存半天有啥意义呢?我们知道MessageQueue的对象在Looper构造函数中实例化的;一个Looper对应一个MessageQueue,所以说Handler发送消息是通过Handler构造函数里拿到的Looper对象的成员MessageQueue的enqueueMessage方法将消息插入队列,也就是说出队列一定也与Handler和Looper和MessageQueue有关系。