Android 线程通信(Handler + Message + Looper) 3 - Handler

参考:

Android 线程通信(Handler + Message + Looper) 0 - 前言

android.os.Handler


Android 使用类 Handler 来发送和处理消息


主要内容:

  1. 构造函数
  2. 处理 Message
  3. 处理 Runnable
  4. 内存泄漏

构造函数

Handler 提供了 7 种构造函数

public Handler()
public Handler(Callback callback)
public Handler(Looper looper)
public Handler(Looper looper, Callback callback)
public Handler(boolean async)
public Handler(Callback callback, boolean async)
public Handler(Looper looper, Callback callback, boolean async)

下面讲解各参数含义

  • Callback

    Handler 提供了一个接口 Callback

    /**
     * Callback interface you can use when instantiating a Handler to avoid
     * having to implement your own subclass of Handler.
     *
     * @param msg A {@link android.os.Message Message} object
     * @return True if no further handling is desired
     */
    public interface Callback {
        public boolean handleMessage(Message msg);
    }
    

    当你不想用子类继承时,可以实现该接口,作为参数传入即可

  • Looper

    提供 Looper 对象作为参数,可以让 Handler 将消息传递给指定 Looper 的消息队列

  • async

    设置 Handler 对象是否同步(这个不太理解它的作用

实现示例如下,在子线程中创建 Handler 对象,使用接口 Callback 实现 handleMessage 方法,并传入主线程的 Looper 对象:

class MyThread extends Thread implements Handler.Callback {
    private static final String TAG = "MyThread";
    Handler handler;

    @Override
    public void run() {
        Looper.prepare();

        Looper.myLooper().setMessageLogging(new LogPrinter(Log.ERROR, TAG));

        handler = new Handler(Looper.getMainLooper(), this);

        Log.e(TAG, "run: " + Thread.currentThread().getName());
        Looper.loop();
    }

    @Override
    public boolean handleMessage(Message msg) {
        Log.e(TAG, "handleMessage: " + Thread.currentThread().getName());
        return false;
    }
}

然后在主线程中启动线程并发送消息:

MyThread thread = new MyThread();
thread.start();

Log.e(TAG, "onCreate: " + Thread.currentThread().getName());
try {
    Thread.sleep(200);
} catch (InterruptedException e) {
    e.printStackTrace();
}

Message msg = Message.obtain(thread.handler, 1, 2, 3);
msg.sendToTarget();

这里写图片描述

由结果可知,虽然 Handler 在子线程中创建,但由于其绑定的消息队列是主线程的,所以处理消息时也在主线程环境下


处理 Message

Handler 类提供了以下方法来发送消息:

public final boolean sendMessage(Message msg)
public final boolean sendMessageDelayed(Message msg, long delayMillis)
public boolean sendMessageAtTime(Message msg, long uptimeMillis)
public final boolean sendMessageAtFrontOfQueue(Message msg)

其中,参数 delayMillis 表示延迟的时间(以毫秒计);参数 uptimeMillis 表示发送消息的时间,即当前时间加上延迟时间(uptimeMillis = SystemClock.uptimeMillis() + delayMillis

如果想要即时处理发送的消息,可以使用方法 sendMessageAtFrontOfQueue

Handler 类也提供了测试消息函数:

public final boolean sendEmptyMessage(int what)
public final boolean sendEmptyMessageDelayed(int what, long delayMillis)
public final boolean sendEmptyMessageAtTime(int what, long uptimeMillis)

参数 what 表示当前消息的类型,参数 delayMillisuptimeMillis 与上面一致

dispatchMessage

发送上面函数后,Handler 会将其加入到消息队列中(如果没有输入 Message, 会在内部创建),然后在 Looper.loop() 方法中调取消息队列消息,并发送给 Handler 处理:

/**
 * 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;
        }

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

        ...

        try {
            msg.target.dispatchMessage(msg);
        } finally {
            if (traceTag != 0) {
                Trace.traceEnd(traceTag);
            }
        }

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

        ...
    }
}

loop() 方法里调用了 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);
    }
}

由之前可知,msg.callback 参数是 Runnable 对象,handleCallback 方法实现如下:

private static void handleCallback(Message message) {
    message.callback.run();
}

即调用它的 run() 方法体(在 Looper 对象对应的线程实现)

同时,它会判断是否在参数 mCallback 有设置,如果有,则调用接口 Callback.handleMessage 方法;否则,调用子类的 handleMessage 方法;

/**
 * Subclasses must implement this to receive messages.
 */
public void handleMessage(Message msg) {
}

处理 Runnable

Handler 也提供了函数可以直接运行 Runnable 对象

public final boolean post(Runnable r)
public final boolean postDelayed(Runnable r, long delayMillis)
public final boolean postAtTime(Runnable r, long uptimeMillis)
public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
public final boolean postAtFrontOfQueue(Runnable r)

参数 delayMillisuptimeMillis 的含义和上面一致

参数 token 用于设置 Messageobj 变量,查看其实现:

public final boolean postAtTime(Runnable r, Object token, long uptimeMillis)
{
    return sendMessageAtTime(getPostMessage(r, token), uptimeMillis);
}

private static Message getPostMessage(Runnable r, Object token) {
    Message m = Message.obtain();
    m.obj = token;
    m.callback = r;
    return m;
}

可以发现,Handler 只是在内部封装了创建 Message 的细节,最终还是调用 Message

同样的,即时处理 Runnable 对象函数 postAtFrontOfQueue 应该也是在内部创建一个 Message 类,然后发送到消息队列:

public final boolean postAtFrontOfQueue(Runnable r)
{
    return sendMessageAtFrontOfQueue(getPostMessage(r));
}

private static Message getPostMessage(Runnable r) {
    Message m = Message.obtain();
    m.callback = r;
    return m;
}

Note:最终 Runnable 对象在消息队列对应的线程中实现


内存泄漏

参考:

Android Weak Handler:可以避免内存泄漏的Handler库

Handler造成Activity泄漏,用弱引用真的有用么?

这部分参考上面两篇博文(以及评论

Handler 在使用过程中出现内存泄露的主要原因是由于消息队列中还存在未处理完的消息

Handler 提供了多个方法来查询和移除未处理的消息

public final boolean hasMessages(int what)
public final boolean hasMessages(int what, Object object)

查询消息队列中是否存在相同 what 属性和 obj 属性值的消息

public final void removeCallbacks(Runnable r)
public final void removeCallbacks(Runnable r, Object token)
public final void removeMessages(int what, Object object) 
public final void removeCallbacksAndMessages(Object token)

同样是根据参数值来移除消息队列中未处理的消息

static 和 弱引用

如果在内部定义 Handler 子类,可以定义为 static;同时还可以定义为弱引用

示例程序如下:

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "MainActivity";

    MyHandler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        handler = new MyHandler(this);

        Message msg = Message.obtain(handler);
        msg.sendToTarget();
    }

    private void handler() {
        Log.e(TAG, "handler: " + Thread.currentThread().getName());
    }

    static class MyHandler extends Handler {
        private WeakReference<MainActivity> weakReference;

        public MyHandler(MainActivity activity) {
            weakReference = new WeakReference<MainActivity>(activity);
        }

        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);

            Log.e(TAG, "handleMessage: " + Thread.currentThread().getName());
            MainActivity activity = weakReference.get();

            if (activity != null) {
                activity.handler();
            }
        }
    }
}

这里写图片描述

猜你喜欢

转载自blog.csdn.net/u012005313/article/details/78421008
今日推荐