Android中的线程机制(Handler Looper)(二)
来源:互联网 发布:指南针全赢数据 编辑:程序博客网 时间:2024/05/27 00:39
在上一篇中我们通过handler的发送消息方法实现了计时器的功能。在子线程中发送更新消息,主线程中来处理消息。那么是不是只能是主线程处理消息呢?其他线程要想处理消息又该如何实现呢?
实际上:消息发送和计划任务提交之后,它们都会进入某线程的消息队列中,我们可以把这个线程称之为目标线程。不论是主线程还是子线程都可以成为目标线程。上例中之所以在主线程中处理消息,是因为我们要更新UI,按照Android中的规定我们必须由主线程更新UI。所以我们让主线程成为了目标线程。
那么如何控制让某个线程成为目标线程呢?
这就引出了Looper的概念。Android系统中实现了消息循环机制,Android的消息循环是针对线程的,每个线程都可以有自己的消息队列和消息循环。Android系统中的通过Looper帮助线程维护着一个消息队列和消息循环。通过Looper.myLooper()得到当前线程的Looper对象,通过Looper.getMainLooper()得到当前进程的主线程的Looper对象。如Looper中的部分源码:
- public class Looper {
- private static final boolean DEBUG = false;
- private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
- // sThreadLocal.get() will return null unless you've called prepare().
- private static final ThreadLocal sThreadLocal = new ThreadLocal();
- final MessageQueue mQueue;
- volatile boolean mRun;
- Thread mThread;
- private Printer mLogging = null;
- private static Looper mMainLooper = null;
- /** Initialize the current thread as a looper.
- * This gives you a chance to create handlers that then reference
- * this looper, before actually starting the loop. Be sure to call
- * {@link #loop()} after calling this method, and end it by calling
- * {@link #quit()}.
- */
- public static final void prepare() {
- if (sThreadLocal.get() != null) {
- throw new RuntimeException("Only one Looper may be created per thread");
- }
- sThreadLocal.set(new Looper());
- }
- public static final void loop() {
- Looper me = myLooper();
- MessageQueue queue = me.mQueue;
- while (true) {
- Message msg = queue.next(); // might block
- //if (!me.mRun) {
- // break;
- //}
- if (msg != null) {
- if (msg.target == null) {
- // No target is a magic identifier for the quit message.
- return;
- }
- if (me.mLogging!= null) me.mLogging.println(
- ">>>>> Dispatching to " + msg.target + " "
- + msg.callback + ": " + msg.what
- );
- msg.target.dispatchMessage(msg);
- if (me.mLogging!= null) me.mLogging.println(
- "<<<<< Finished to " + msg.target + " "
- + msg.callback);
- msg.recycle();
- }
- }
- }
前面提到每个线程都可以有自己的消息队列和消息循环,然而我们自己创建的线程默认是没有消息队列和消息循环的(及Looper),要想让一个线程具有消息处理机制我们应该在线程中先调用Looper.prepare()来创建一个Looper对象,然后调用Looper.loop()进入消息循环。如上面的源码所示。示例代码如下:
- class LooperThread extends Thread {
- public Handler mHandler;
- public void run() {
- Looper.prepare();
- mHandler = new Handler() {
- public void handleMessage(Message msg) {
- // process incoming messages here
- }
- };
- Looper.loop();
- }
当我们用Handler的构造方法创建Handler对象时,指定handler对象与哪个具有消息处理机制的线程(具有Looper的线程)相关联,这个线程就成了目标线程,可以接受消息和计划任务了。Handler中的构造方法如下:
- public Handler() {
- if (FIND_POTENTIAL_LEAKS) {
- final Class<? extends Handler> klass = getClass();
- if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
- (klass.getModifiers() & Modifier.STATIC) == 0) {
- Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
- klass.getCanonicalName());
- }
- }
- mLooper = Looper.myLooper();
- if (mLooper == null) {
- throw new RuntimeException(
- "Can't create handler inside thread that has not called Looper.prepare()");
- }
- mQueue = mLooper.mQueue;
- mCallback = null;
- }
- public Handler(Looper looper) {
- mLooper = looper;
- mQueue = looper.mQueue;
- mCallback = null;
- }
在上述的计时器的例子中,之所以可以在主线程中处理消息而我们自己并没有调用Looper.prepare()等方法,是因为Android系统在Activity启动时为其创建一个消息队列和消息循环,当我们用无参的Handler构造方法创建对象时又用了当前线程的Looper对象,及将handler与主线程中的Looper对象进行了关联。
android中是使用Looper机制来完成消息循环的,但每次创建线程时都先初始化Looper比较麻烦,因此Android为我们提供了一个HandlerThread类,他封装了Looper对象,是我们不用关心Looper的开启和释放问题。
不管是主线程还是其他线程只要有Looper的线程,别的线程就可以向这个线程的消息队列中发送消息和任务。
我们使用HandlerThread类代替上一篇文章中的子线程,并用HandlerThread类中的Looper对象构造Handler,则接受消息的目标线程就不是主线程了,而是HandlerThread线程。代码如下:
- public class clockActivity extends Activity {
- /** Called when the activity is first created. */
- private String TAG="clockActivity";
- private Button endButton;
- private TextView textView;
- private int timer=0;
- private boolean isRunning=true;
- private Handler handler;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- endButton=(Button)findViewById(R.id.endBtn);
- textView=(TextView)findViewById(R.id.textview);
- endButton.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- isRunning=false;
- }
- });
- HandlerThread thread=new HandlerThread("myThread");
- handler=new Handler(thread.getLooper());//与HandlerThread中的Looper对象关联
- thread.start();
- Runnable r=new Runnable(){
- @Override
- public void run() {
- // TODO Auto-generated method stub
- if(isRunning){
- textView.setText("走了"+timer+"秒");
- timer++;
- handler.postDelayed(this, 1000);//提交任务r,延时1秒执行
- }
- }
- };
- handler.postDelayed(r, 1000);
- }
- }
此时处理任务会在handlerThread线程中完成。当然这个例子会出线异常:依然是因为在非主线程中更新了UI。这样做只是为了大家能够理解这种机制。
深入理解Android消息处理机制对于应用程序开发非常重要,也可以让我们对线程同步有更加深刻的认识,希望这篇文章可以对朋友们有所帮助。
- Android中的线程机制(Handler Looper)(二)
- Android中的线程机制(Handler Looper)(二)
- Android线程间通信机制(handler,looper)
- Handler,Looper,MessageQueue,android中的消息机制以及源码分析(二)
- Android 中消息处理机制-Looper、Handler、Thread (二)
- Android 中消息处理机制-Looper、Handler、Thread (二)
- Android 中消息处理机制-Looper、Handler、Thread (二)
- Android线程间通信机制(Handler Looper )
- Android线程间通信机制(Handler Looper )
- Android中的Handler机制(二)
- Android:Looper, Handler, And HandlerThread(二)
- Android深入--Handler机制简析(Handler、Looper、MessageQueue)
- Android中的Handler,Looper,Message机制
- Android中的Handler,Looper,Message机制
- Android中的Thread, Looper和Handler机制
- android消息处理机制学习(二)-Handler,Message,MessageQueue,Looper图例讲解
- android Looper Handler机制
- android之多线程工作(二)handler messge机制
- ADO.NET-数据库操纵工具
- hive学习之五:java通过zookeeper获取active namenode地址。
- 使用cocoapods系列 一
- nginx-openresty-keynote
- 链表和数组的区别在哪里?
- Android中的线程机制(Handler Looper)(二)
- iOS开发中自定义Log
- Spring3 整合MyBatis3 配置多数据源 动态选择SqlSessionFactory
- 【Android】安全退出应用程序
- nginx源码分析(1)——启动过程--todo
- 编码总结
- 装箱和拆箱
- 基于快速排序思想的三个算法题
- Android日期时间类,解决其他时间类时间会出现误差的bug