在 android 中,不可以在子线程中更新 UI 的操作,否则会报错或者异常信息。

在这种情况下,我们会使用 Handler(在 UI 线程创建该对象) 接收子线程的消息更新 UI.

可以看出,这是子线程通知主线程,而主线程没有直接通知子线程,那麽我们如何做到这一点?这样有什么好处?

好处,很明显。主线程中如果有些耗时的操作,我们可以让子线程去做,这时,主线程就可以通知子线程了!


实现这种操作的方式有很多,今天主要想说说 HandlerThread 与 Handler 的配合使用方法。


在主线程中,可以创建 HandlerThread 对象:

view plain print ?
  1. HandlerThreadmHandlerThread=newHandlerThread("sub_thread");
  2. mHandlerThread.start();

这样,就开启了一个子线程,该线程的名字就是 sub_thread.


然后,我们实现一个继承自 Handler 的 MyHandler 类:

view plain print ?
  1. classMyHandlerextendsHandler{
  2. publicMyHandler(){
  3. super();
  4. }
  5. publicMyHandler(Looperlooper){
  6. super(looper);
  7. }
  8. @Override
  9. publicvoidhandleMessage(Messagemsg){
  10. //super.handleMessage(msg);
  11. if(msg.what==MSG_WHAT){
  12. Bundlebundle=msg.getData();
  13. Stringinfo=bundle.getString("main");
  14. Log.d("mark","我接受任务:"+info);
  15. }
  16. }
  17. }

最后,使用 Message 来传递消息,MyHandler 会根据情况处理 Message.


完整代码:

view plain print ?
  1. packagemark.zhang;
  2. importandroid.app.Activity;
  3. importandroid.os.Bundle;
  4. importandroid.os.Handler;
  5. importandroid.os.HandlerThread;
  6. importandroid.os.Looper;
  7. importandroid.os.Message;
  8. importandroid.util.Log;
  9. publicclassHandlerThreadActivityextendsActivity{
  10. privatestaticfinalintMSG_WHAT=1;
  11. @Override
  12. publicvoidonCreate(BundlesavedInstanceState){
  13. super.onCreate(savedInstanceState);
  14. setContentView(R.layout.main);
  15. //创建对象,并启动该线程
  16. HandlerThreadmHandlerThread=newHandlerThread("sub_thread");
  17. mHandlerThread.start();
  18. //获取Looper对象
  19. MyHandlermHandler=newMyHandler(mHandlerThread.getLooper());
  20. //创建Bundle对象,传递数据
  21. Bundlebundle=newBundle();
  22. bundle.putString("main","我这边事情太多,麻烦你帮忙处理一下!");
  23. //发送消息
  24. Messagemsg=newMessage();
  25. msg.what=MSG_WHAT;
  26. msg.setData(bundle);
  27. msg.setTarget(mHandler);
  28. msg.sendToTarget();
  29. Log.d("mark","UI----"+"threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
  30. }
  31. /**
  32. *该Handler调用handleMessage方法运行在子线程
  33. *
  34. *@authormark
  35. */
  36. classMyHandlerextendsHandler{
  37. publicMyHandler(){
  38. super();
  39. }
  40. /*这个构造方法必须有*/
  41. publicMyHandler(Looperlooper){
  42. super(looper);
  43. }
  44. @Override
  45. publicvoidhandleMessage(Messagemsg){
  46. if(msg.what==MSG_WHAT){
  47. Bundlebundle=msg.getData();
  48. //接收消息
  49. Stringinfo=bundle.getString("main");
  50. Log.d("mark","handleMessage---"+"threadName:"+Thread.currentThread().getName()+",threadId:"+Thread.currentThread().getId());
  51. Log.d("mark","我接受任务:"+info);
  52. }
  53. }
  54. }
  55. }

这里,我们思考一个问题,代码:

view plain print ?
  1. //获取Looper对象
  2. MyHandlermHandler=newMyHandler(mHandlerThread.getLooper());

获取 Looper 对象,使用的是 HandlerThread 对象的 getLooper 对象。为什么不直接这样:

view plain print ?
  1. //获取Looper对象
  2. MyHandlermHandler=newMyHandler(getMainLooper());

如果这样做的话,打印信息如下:

view plain print ?
  1. D/mark(21852):UI----threadName:main,threadId:1
  2. D/mark(21852):handleMessage---threadName:main,threadId:1
  3. D/mark(21852):我接受任务:我这边事情太多,麻烦你帮忙处理一下!

可见,此时的 handleMessage 是在主线程中运行的。每个主线程默认有一个 Looper,也就是说在主线程中,下面代码是等效的:

view plain print ?
  1. MyHandlermHandler=newMyHandler(getMainLooper());
  2. MyHandlermHandler=newMyHandler();

但是子线程需要手动获取如:

view plain print ?
  1. MyHandlermHandler=newMyHandler(mHandlerThread.getLooper());

实现主线程、子线程双向通信可以在各自的线程中分别是用 Handler 来传递信息和处理消息。



更多相关文章

  1. Android中需要手动关闭的地方总结
  2. 十大技巧优化Android(安卓)App性能
  3. android手机开发课小结
  4. 从架构师的角度分析Android(安卓)Handler 源码的正确姿势
  5. 《第一行代码》学习笔记之服务
  6. Android中Handler,Looper,MessageQueue和Thread
  7. Android(安卓)中使用 dlib+opencv 实现动态人脸检测
  8. Android内存泄漏检测及修复(转载)
  9. Android消息机制之HandlerThread

随机推荐

  1. android > intent > 自动跳转到 系统 设
  2. android获取手机屏幕的宽度及高度
  3. 短信拦截
  4. 类似股票的实时动态折线图
  5. Android通过代码自动连接WiFi
  6. Android service: startService的代码实
  7. Android TextView自定义选中弹出菜单记笔
  8. 【Android】创建Popwindow弹出菜单的两种
  9. Android开发者指南(10) —— Android(安
  10. Android自带语音播报