看Android开发笔记之:消息循环与Looper的详解有感
2016-02-14 15:36
555 查看
看完Android开发笔记之:消息循环与Looper的详解后的总结,原文和原文作者没有找到,找到的都是跟这个类似的转载。
先上代码
这个代码来自上面引用的文章,我只是添加了两处打印
先说一下这个代码的运行结果,在action的点击事件响应后,手机屏幕开始输出”.......“之后输出结束的文字,end按钮的点击事件响应后,等待mHandler的handlemessage方法执行完毕,控制台输出“调用Looper.loop()之后”,如果不点击end,则不会输出,也就是looper的quite的方法没有执行之前,looper.loop()之后的方法是不会被执行的。多次点击action,并不会影响当前正在执行的mHandler.handlermessage()方法,而是按顺序执行多次handlemessage方法。而只要点了end,那么当前mHandler.handlemessage方法执行完毕后即输出“调用Looper.loop()之后”,而不再执行后续的mHanlder.handlemessage()方法,估计原因是looper已经释放。
另外,当我把线程中Looper拿掉后,报错,提醒我handler在子线程中未调用Looper.prepare之前不能调用(大概的意思,原话不是这个),也就是说looper在这里是为了维护子线程的消息队列。
最后,在实际项目中,我对handler的调用基本都是在activity中初始化,然后传到thread中,然后发送message,而这个原理其实跟上面中的并没有什么差别,因为最后负责ui显示的handler还是得在activity中初始化,然后传到thread,在thread中发送message,所以还是没搞明白looper在实际应用的中有哪些场景...有人能看到我的疑问的话还请劳烦告知一下,谢谢
先上代码
package com.example.gulei.myviewdraghelperdemo; import android.app.Activity; import android.os.Bundle; import android.os.Handler; import android.os.Looper; import android.os.Message; import android.os.SystemClock; import android.text.TextUtils; import android.util.Log; import android.view.View; import android.widget.Button; import android.widget.TextView; /** * Created by gulei on 2016/2/14. */ public class LooperDemoActivity extends Activity { private WorkerThread mWorkerThread; private TextView mStatusLine; private Handler mMainHandler; @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.activity_looper); mMainHandler = new Handler() { @Override public void handleMessage(Message msg) { String text = (String) msg.obj; if (TextUtils.isEmpty(text)) { return; } mStatusLine.setText(text); } }; mWorkerThread = new WorkerThread(); final Button action = (Button) findViewById(R.id.looper_demo_action); action.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mWorkerThread.executeTask("please do me a favor"); } }); final Button end = (Button) findViewById(R.id.looper_demo_quit); end.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { mWorkerThread.exit(); } }); mStatusLine = (TextView) findViewById(R.id.looper_demo_displayer); mStatusLine.setText("Press 'do me a favor' to execute a task, press 'end of service' to stop looper thread"); } @Override public void onDestroy() { super.onDestroy(); mWorkerThread.exit(); mWorkerThread = null; } private class WorkerThread extends Thread { protected static final String TAG = "WorkerThread"; private Handler mHandler; private Looper mLooper; public WorkerThread() { start(); } public void run() { // Attention: if you obtain looper before Looper#prepare(), you can still use the looper // to process message even after you call Looper#quit(), which means the looper does not //really quit. Looper.prepare(); // So we should call Looper#myLooper() after Looper#prepare(). Anyway, we should put all stuff between Looper#prepare() // and Looper#loop(). // In this case, you will receive "Handler{4051e4a0} sending message to a Handler on a dead thread // 05-09 08:37:52.118: W/MessageQueue(436): java.lang.RuntimeException: Handler{4051e4a0} sending message // to a Handler on a dead thread", when try to send a message to a looper which Looper#quit() had called, // because the thread attaching the Looper and Handler dies once Looper#quit() gets called. mLooper = Looper.myLooper(); // either new Handler() and new Handler(mLooper) will work mHandler = new Handler(mLooper) { @Override public void handleMessage(Message msg) { /* * Attention: object Message is not reusable, you must obtain a new one for each time you want to use it. * Otherwise you got "android.util.AndroidRuntimeException: { what=1000 when=-15 4000 ms obj=it is my please * to serve you, please be patient to wait!........ } This message is already in use." */ // Message newMsg = Message.obtain(); StringBuilder sb = new StringBuilder(); sb.append("it is my please to serve you, please be patient to wait!\n"); Log.e(TAG, "workerthread, it is my please to serve you, please be patient to wait!"); for (int i = 1; i < 100; i++) { sb.append("."); Message newMsg = Message.obtain(); newMsg.obj = sb.toString(); mMainHandler.sendMessage(newMsg); Log.e(TAG, "workthread, working" + sb.toString()); SystemClock.sleep(100); } Log.e(TAG, "workerthread, your work is done."); sb.append("\nyour work is done"); Message newMsg = Message.obtain(); newMsg.obj = sb.toString(); mMainHandler.sendMessage(newMsg); } }; Looper.loop(); System.out.println("调用Looper.loop()之后"); } public void exit() { if (mLooper != null) { mLooper.quit(); mLooper = null; } } // This method returns immediately, it just push an Message into Thread's MessageQueue. // You can also call this method continuously, the task will be executed one by one in the // order of which they are pushed into MessageQueue(they are called). public void executeTask(String text) { if (mLooper == null || mHandler == null) { Message msg = Message.obtain(); msg.obj = "Sorry man, it is out of service"; mMainHandler.sendMessage(msg); return; } System.out.println("开始执行任务"); Message msg = Message.obtain(); msg.obj = text; mHandler.sendMessage(msg); } } }
这个代码来自上面引用的文章,我只是添加了两处打印
先说一下这个代码的运行结果,在action的点击事件响应后,手机屏幕开始输出”.......“之后输出结束的文字,end按钮的点击事件响应后,等待mHandler的handlemessage方法执行完毕,控制台输出“调用Looper.loop()之后”,如果不点击end,则不会输出,也就是looper的quite的方法没有执行之前,looper.loop()之后的方法是不会被执行的。多次点击action,并不会影响当前正在执行的mHandler.handlermessage()方法,而是按顺序执行多次handlemessage方法。而只要点了end,那么当前mHandler.handlemessage方法执行完毕后即输出“调用Looper.loop()之后”,而不再执行后续的mHanlder.handlemessage()方法,估计原因是looper已经释放。
另外,当我把线程中Looper拿掉后,报错,提醒我handler在子线程中未调用Looper.prepare之前不能调用(大概的意思,原话不是这个),也就是说looper在这里是为了维护子线程的消息队列。
最后,在实际项目中,我对handler的调用基本都是在activity中初始化,然后传到thread中,然后发送message,而这个原理其实跟上面中的并没有什么差别,因为最后负责ui显示的handler还是得在activity中初始化,然后传到thread,在thread中发送message,所以还是没搞明白looper在实际应用的中有哪些场景...有人能看到我的疑问的话还请劳烦告知一下,谢谢
相关文章推荐
- Android 接入支付宝支付只需十分钟
- Android Studio发布项目到jcenter升级版
- android的Unable to instantiate activity ComponentInfo异常
- android SharedPreferences详解
- android.intent.category.LAUNCHER的作用
- Android 仿知乎日报在切换Fragment页面,按back返回时,同步修改Toolbar的title。
- 【读书笔记】【Android 开发艺术探索】第11章Android 的线程和线程池
- [读书笔记]《Android开发艺术探索》第四章笔记
- “Genymotion运行Android模拟器一直卡在开机界面”的解决办法
- Android Touch事件传递机制
- Android屏幕适配
- Android本地数据存储
- Android反编译看看手Q口令红包的实现原理
- Android获取手机的基本信息
- Android编程规范与常用技巧
- android开发环境搭建时连接不上Google解决办法
- Android 的电池消耗优化 II-监测电量等级和充电状态
- android style的继承方式 点(.)和parent
- android:px,dp(dip),sp的区别
- android系统启动流程图