第十章 Android的消息机制

Android的消息机制主要是指Handler的运行机制。在日常开发中经常是在子线程中执行完一些耗时操作后(网络请求,I/O操作等)需要更新ui,由于不能在子线程中更新ui,这时就需要handler将更新ui的操作切换到主线程中执行。

它的主要作用是将一个任务切换到某个指定的线程中处理。

Handler的运行需要底层MessageQueue和Looper的支持。

MessageQueue 消息队列,它存储了一组消息,主要做消息插入,删除工作,但它本质是单链表结构。

Looper 消息循环。MessageQueue只是用于存储消息,它并不处理消息,Looper用于处理消息,它以无限循环的方式查找是否有新消息,如果有就处理新消息,否则就一直等待。在Looper中还有一个ThreadLocal的概念。

static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();

ThreadLocal可以在不同线程中互不干扰的存储并提供数据,通过ThreadLocal可以获取到每个线程的Looper.

线程中默认是没有Looper的,要使用Handler必须为线程创建Looper。

在主线程中(ActivityThread)默认可以使用Handler是因为主线程在创建时初始化了Looper.

public static void main(String[] args) {
    // Make sure TrustedCertificateStore looks in the right place for CA certificates
    final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
    TrustedCertificateStore.setDefaultUserDirectory(configDir);
    Process.setArgV0("<pre-initialized>");
    Looper.prepareMainLooper();//在这里,在这里
    ActivityThread thread = new ActivityThread();
    thread.attach(false);

Handler的工作过程

在这里插入图片描述

可以通过handler的post()或sendMessage()的方式将一个message投递到Handler内部的Looper中处理。

Handler handler=new Handler();
handler.post(new Runnable() {
   @Override
   public void run() {
   //do anything you want     
   }
});
handler.sendMessage(new Message());

通过查看源码发现这两种方法最终都会调用下面的方法:

enqueueMessage(queue, msg, uptimeMillis);

这个方法是将新的消息插入到消息队列中。

Looper的loop方法是一个死循环,唯一跳出死循环的情况是MessageQueue.next()方法返回了null,当next()方法返回不为null时说明有新的消息到来,这时Handler的dispatchMessage()方法会被调用,也就是Runnable方法或者Handler的handleMessage方法被调用。因为Looper是运行在Handler所在的线程中,所以任务就被切换到了Handler所在的线程中。源码如下:

Looper中的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;
    ........
    ........
    ........
    for (;;) {
        Message msg = queue.next(); // might block
        if (msg == null) {
            // No message indicates that the message queue is quitting.
            return;
        }
		.......
		.......
		.......
		.......
        try {
            msg.target.dispatchMessage(msg);
           .........
        }
        .........
    }
}

Handler中的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);
    }
}

Handler存在的问题:

如果Activity已经finish,但这时handler的任务可能并没有完(例如延时),这时就会出现内存泄漏。如何避免:

  1. 使用静态内部类创建Handler对象,并持有activity弱引用

    在Java中非静态内部类会隐性地持有外部类的引用,而非静态内部类则不会。

    private static class NoLeakHandler extends Handler{
            private WeakReference<NoLeakActivity> mActivity;
    
            public NoLeakHandler(NoLeakActivity activity){
                mActivity = new WeakReference<>(activity);
            }
    
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
            }
        }
    

2.在activity finish时及时的清除消息

@Override
protected void onDestroy() {
   super.onDestroy();
   handler.removeCallbacksAndMessages(null);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值