在android主线程中做太耗时的操作会引起ANR崩溃,为了进行线程间通信,就需要用到handler消息处理机制。消息传递分为两类,一种是从MainThread向WorkerThread传递消息,而另外一种是从WorkerThread向MainThread传递消息。由于主线程主要负责UI相关的事件,如用户的点击事件,屏幕触摸事件等,当捕捉到用户动作后将会分发到相应的组件进行处理。因此,主线程也叫UI线程。
首先,我来说一下handler工作流程。还是用流程图的方式来表示,这样看起来一目了然。
handler(发送消息)➡MessageQueue(消息队列)➡Looper(取出消息)➡交给handler(调用handlerMessage方法去处理)➡更新UI界面
简单地总结一下,就是在子线程中通过handler去发送一条消息到主线程,这条消息就会进入到消息队列MessageQueue中,然后在主线程中调用Looper对象来管理消息队列,不断的从消息队列中取出消息,并将消息分给对应的Handler来处理,最后更新UI界面。
- 从WorkThread向MainThread发送消息
1 packagecom.example.handlertest; 2 3 importandroid.app.Activity; 4 importandroid.os.Bundle; 5 importandroid.os.Handler; 6 importandroid.os.Message; 7 importandroid.view.Menu; 8 importandroid.view.View; 9 importandroid.view.View.OnClickListener; 10 importandroid.widget.Button; 11 importandroid.widget.TextView; 12 13 public class MainActivity extendsActivity { 14 15 privateButton mybutton; 16 privateTextView mytextview; 17 privateHandler handler; 18 @Override 19 protected voidonCreate(Bundle savedInstanceState) { 20 super.onCreate(savedInstanceState); 21 setContentView(R.layout.activity_main); 22 mytextview=(TextView)findViewById(R.id.textview1); 23 mybutton=(Button)findViewById(R.id.button1); 24 mybutton.setOnClickListener(newButtonListener()); 25 handler=newfirstHandler(); 26 } 27 //不能直接在WorkerThread中去更新UI,所以使用handler来处理 28 class firstHandler extendsHandler 29 { 30 @Override 31 public voidhandleMessage(Message msg) { 32 //TODO 在textview中显示获取到的数据 33 super.handleMessage(msg); 34 System.out.println("handlerMessage--->"+Thread.currentThread().getName()); 35 String ss=(String)msg.obj; 36 mytextview.setText(ss); 37 } 38 } 39 class ButtonListener implementsOnClickListener 40 { 41 @Override 42 public voidonClick(View v) { 43 //TODO Auto-generated method stub 44 Thread td=newNetWorkThread(); 45 td.start(); 46 } 47 } 48 //开启一个子线程WorkerThread 49 class NetWorkThread extendsThread 50 { 51 @Override 52 public voidrun() { 53 //TODO 让线程休眠2s,利用handler向主线程发送消息 54 System.out.println("handlerMessage--->"+Thread.currentThread().getName()); 55 super.run(); 56 try 57 { 58 Thread.sleep(1*1000); 59 } 60 catch(InterruptedException e) 61 { 62 e.printStackTrace(); 63 } 64 String s="全家福"; 65 Message msg=handler.obtainMessage(); 66 msg.obj=s; 67 handler.sendMessage(msg); 68 } 69 } 70 }
- 从MainThread向WorkerThread发送消息
1 packagecom.example.s2_e2; 2 3 importandroid.app.Activity; 4 importandroid.os.Bundle; 5 importandroid.os.Handler; 6 importandroid.os.Looper; 7 importandroid.os.Message; 8 importandroid.view.View; 9 importandroid.view.View.OnClickListener; 10 importandroid.widget.Button; 11 importandroid.widget.TextView; 12 13 public class MainActivity extendsActivity { 14 15 privateButton button1; 16 privateHandler handler; 17 @Override 18 protected voidonCreate(Bundle savedInstanceState) { 19 super.onCreate(savedInstanceState); 20 setContentView(R.layout.activity_main); 21 22 button1=(Button)findViewById(R.id.button1); 23 button1.setOnClickListener(newButtonListener()); 24 WorkerThread wd=newWorkerThread(); 25 wd.start(); 26 } 27 class ButtonListener implementsOnClickListener 28 { 29 30 @Override 31 public voidonClick(View v) { 32 33 System.out.println("clickThread is--->"+Thread.currentThread().getName()); 34 Message msg=handler.obtainMessage(); 35 handler.sendMessage(msg); 36 } 37 38 } 39 40 class WorkerThread extendsThread 41 { 42 @Override 43 public voidrun() { 44 //准备Looper对象 45 Looper.prepare(); 46 //在WorkThread当中生成一个Handler对象 47 handler=newHandler(){ 48 @Override 49 public voidhandleMessage(Message msg) { 50 51 System.out.println("receive message--->"+Thread.currentThread().getName()); 52 } 53 }; 54 //Looper对象不断的从消息队列中取出消息对象,使用Handler的sendMessage来处理消息对象 55 //若没有消息则会发生阻塞 56 Looper.loop(); 57 } 58 59 } 60 }
另外,不得不提的是Handler的Post方法。
1 packagecom.example.s2_e2; 2 3 importandroid.app.Activity; 4 importandroid.os.Bundle; 5 importandroid.os.Handler; 6 importandroid.os.Message; 7 importandroid.view.View; 8 importandroid.view.View.OnClickListener; 9 importandroid.widget.Button; 10 importandroid.widget.TextView; 11 12 public class MainActivity extendsActivity { 13 14 //问题1.如何把一个Runnable对象放置在消息队列中? 15 //问题2.Looper取出了带有r的Message对象之后,做了什么? 16 privateButton button1; 17 Handler handler=newHandler(); 18 @Override 19 protected voidonCreate(Bundle savedInstanceState) { 20 super.onCreate(savedInstanceState); 21 setContentView(R.layout.activity_main); 22 23 button1=(Button)findViewById(R.id.button1); 24 button1.setOnClickListener(newButtonListener()); 25 } 26 class ButtonListener implementsOnClickListener 27 { 28 @Override 29 public voidonClick(View arg0) { 30 MyThread td=newMyThread(); 31 td.start(); 32 } 33 } 34 class MyThread extendsThread 35 { 36 @Override 37 public voidrun() { 38 Runnable r=newRunnable() 39 { 40 @Override 41 public voidrun() { 42 //这里可以写更新UI的内容 43 System.out.println("currentThread is"+MyThread.currentThread().getName()); 44 } 45 }; 46 //1:该方法生成了一个Message对象,将r赋值给Message对象的callback属性,把Message对象放到消息队列中 47 //2:取出Message对象之后调用了dispatchMessage方法。由于callback不为空,所以执行了msg.callback方法 48 handler.post(r); 49 } 50 } 51 }