看Android开发笔记之:消息循环与Looper的详解有感

看完Android开发笔记之:消息循环与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=-15ms 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在实际应用的中有哪些场景...有人能看到我的疑问的话还请劳烦告知一下,谢谢

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值