消息传递机制以及Thread和handler的一些区别

执行耗时操作,相信很多人都用过Thread和handler,但是两者的区别可能不是很清楚,我自己刚开始也是这样子,经历一番baidu,翻书,大致有了一些看法,thread是通过开辟一个新的线程,然后再run方法里面执行耗时操作,这个时候的工作线程是非UI线程的。那我们使用Thread的时候,有两种常用的方法,一种是直接修改run方法
Thread thread=new Thread(){
			@Override
			public void run() {
				// 直接添加执行代码
			}
		};

一种是通过新建runnable,执行里面的方法。这种可以协调系统资源,如:

Thread thread=new Thread(new Runnable() {
			
			@Override
			public void run() {
				// TODO Auto-generated method stub
				
			}
		});
说回handler,handler的话不一定在子线程,他的工作线程决定与它的创建线程,所以当我们创建handler来执行UI更新的时候,就必须要在UI线程创建了,不然你在子线程创建Handler,它的工作线程为非UI线程,不就不符合非UI线程不能执行更新UI的规则了吗?而handler的使用方法分为post(runnable)和send(Message),其实本质是一样的,个人觉得后者增加了一种类型的判断。还有一点,
private Handler myHandler1 = new Handler(new MyHandlerCallback());
    private Handler myHandler2 = new MyHandler();
 
    private class MyHandlerCallback implements Handler.Callback {
        @Override
        public boolean handleMessage(Message msg) {
            // Handle messages.
            return false;
        }
    }
 
    private class MyHandler extends Handler {
        @Override
        public void handleMessage(Message msg) {
            // Handle messages.
        }
    }
CallBack其实也是实现Runnable接口的,如果我们不想派生Handler子类的话就可以通过CallBack来实现。
那么接下来让我们来说一下今天的主题,消息传递机制。

Handler是消息机制的上层接口,这使得在开发过程只需要和Handler交互就可。很多人认为Handler的作用是更新UI,那只不过是它比较常用的一点而已,执行耗时操作,都需要在子线程中进行。说到Android的消息机制,主要指Handler的运行机制,Handler的运行需要底层的MessageQueue和Looper的支撑,MessageQueue只是一个消息存储单元,内部是通过链表的信息来存储消息列表的,由于MessageQueue只是存储单元,就需要Looper去进行消息的处理,Looper会以无限循环的形式来查看是否有新的消息,有就会去处理,没有就阻塞,直到有消息来。所以当我们在子线程新建一个handler的时候,就需要通过Looper.prepare()为当前线程创建一个Looper,接着通过Looper.loop()来开启MessageQueue,如下:

Thread thread=new Thread(new Runnable() {
			
			@Override
			public void run() {
				Looper.prepare();
				Handler handler=new Handler();
				Looper.loop();
			}
		});
有的人会说为什么我在主线程新建handler的时候不需要looper的,你确定吗?让我们来看一下ActivityThread的入口方法main:
public static final void main(String[] args) {
        SamplingProfilerIntegration.start();
       ……
        Looper.prepareMainLooper();
        if (sMainThreadHandler == null) {
            sMainThreadHandler = new Handler();
        }
        ActivityThread thread = new ActivityThread();
        thread.attach(false);
       ……
        Looper.loop();
       ……
        thread.detach();
        ……
        Slog.i(TAG, "Main thread of " + name + " is now exiting");
    }
程序已经默认为我们新建一个looper了。至于ActivityThread的源码在IDE中默认不给修改,也就看不了了,有兴趣的读者可以去下载源码看一下。

Looper最重要的一个方法是loop方法,只有调用了loop后,消息循环才会真正起作用,实现如下:

/**
     * Run the message queue in this thread. Be sure to call
     * {@link #quit()} to end the loop.
     */
    public static void loop() {
        final Looper me = myLooper();
        if (me == null) {
            throw new RuntimeException("No Looper; Looper.prepare() wasn't called on this thread.");
        }
        final MessageQueue queue = me.mQueue;

        // Make sure the identity of this thread is that of the local process,
        // and keep track of what that identity token actually is.
        Binder.clearCallingIdentity();
        final long ident = Binder.clearCallingIdentity();

        for (;;) {
            Message msg = queue.next(); // might block
            if (msg == null) {
                // No message indicates that the message queue is quitting.
                return;
            }

            // This must be in a local variable, in case a UI event sets the logger
            Printer logging = me.mLogging;
            if (logging != null) {
                logging.println(">>>>> Dispatching to " + msg.target + " " +
                        msg.callback + ": " + msg.what);
            }

            msg.target.dispatchMessage(msg);

            if (logging != null) {
                logging.println("<<<<< Finished to " + msg.target + " " + msg.callback);
            }

            // Make sure that during the course of dispatching the
            // identity of the thread wasn't corrupted.
            final long newIdent = Binder.clearCallingIdentity();
            if (ident != newIdent) {
                Log.wtf(TAG, "Thread identity changed from 0x"
                        + Long.toHexString(ident) + " to 0x"
                        + Long.toHexString(newIdent) + " while dispatching to "
                        + msg.target.getClass().getName() + " "
                        + msg.callback + " what=" + msg.what);
            }

            msg.recycle();
        }
    }
loop里面就一个死循环,唯一跳出循环的就是MessageQueue的next方法返回null,looper的quit和quitSafely方法都可以使next方法为空,字面就理解两者的区别了,一种是立刻退出,一种是执行完消息队列才退出,当没有消息的时候,next方法会阻塞在那里当next方法返回了新的消息,looper就会去处理它:msg.target.dispatchMessage(msg),这里的msg.target指发送这条Handler的对象,而Handler的dispatchMessage方法是在创建Handler时所用的looper中使用的,这样子就把我们要执行的操作换到指定线程执行了。下面我们看一下dispatchMessage方法:
/**
     * Handle system messages here.
     */
    public void dispatchMessage(Message msg) {
        if (msg.callback != null) {
            handleCallback(msg);
        } else {
            if (mCallback != null) {
                if (mCallback.handleMessage(msg)) {
                    return;
                }
            }
            handleMessage(msg);
        }
    }
检测Message的callBack是否为空,不为null就通过handlerCallBack处理。Message的callBack是一个Runnable对象,这个在上文说过,实际就是post方法所传递的Runnable参数。
private static void handleCallback(Message message) {
        message.callback.run();
    }
其次检测mCallBack是否为空,不为null就调用mCallBack的handlerMessage方法来处理,因为CallBack是个接口
public interface Callback {
        public boolean handleMessage(Message msg);
    }
然后我们重写handlerMessage方法即可实现自己的代码逻辑,到此,Android的消息机制就说完了,在此特别感谢《Android开发技术探索》对我的帮助。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值