Android Handler源码分析

为什么Android只能在UI线程更新UI?

  1. 解决多线程并发问题
  2. 提高界面更新的性能
  3. 架构设计简单

Handler消息模型

《Android Handler源码分析》

Looper类

《Android Handler源码分析》

主要成员变量和方法:

    private static final String TAG = "Looper";

    // sThreadLocal.get() will return null unless you've called prepare().
    static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>();
    private static Looper sMainLooper;  // guarded by Looper.class

    final MessageQueue mQueue;
    final Thread mThread;
    volatile boolean mRun;

    private Printer mLogging;

Looper:prepare()

每个线程只能有一个Looper类的实例对象,Looper类的实例必须通过prepare()方法创建,保存在sThreadLocal中。

一个线程多次调用prepare()方法会抛出异常。

     /** 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 void prepare() {
        prepare(true);
    }

    private static void prepare(boolean quitAllowed) {
        if (sThreadLocal.get() != null) {
            throw new RuntimeException("Only one Looper may be created per thread");
        }
        sThreadLocal.set(new Looper(quitAllowed));
    }

Looper:loop()

loop()方法:静态方法,分发消息队列中的消息。其中有一个无限for循环,取出消息队列中的消息,分发消息。

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

Handler类

  1. 构造Handler对象,需要两个参数:线程的Looper对象、消息的处理函数。若不指定Looper对象,会使用当前线程的Looper对象。消息的处理函数不是必须的。

《Android Handler源码分析》

《Android Handler源码分析》

简单的Handler代码

import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {

    private TextView textView;
    private Button button;

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

        textView = (TextView) findViewById(R.id.textView);
        button = (Button) findViewById(R.id.button1);

        final Handler handler = new Handler() {

            @Override
            public void handleMessage(Message msg) {
                if (msg.what == 1) {
                    textView.setText("单击,过了5s");
                }
                if (msg.what == 2) {
                    textView.setText("长按,过了5s");
                }
            }
        };

        // button单击,发送1
        button.setOnClickListener(new View.OnClickListener() {

            public void onClick(View v) {

                new Thread() {
                    public void run() {

                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        handler.sendEmptyMessage(1);

                    };

                }.start();
            }
        });

        // button长按,发送2
        button.setOnLongClickListener(new View.OnLongClickListener() {

            public boolean onLongClick(View v) {

                new Thread() {
                    public void run() {

                        try {
                            Thread.sleep(5000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        handler.sendEmptyMessage(2);

                    };

                }.start();

                // 返回true,不会继续触发click
                return true;
            }
        });
    }
}

主线程向子线程发送消息

我们常用的,都是子线程向主线程发送消息。那么,我们能够从主线程向子线程中发送消息么?

import android.app.Activity;
import android.os.Bundle;
import android.widget.Button;
import android.widget.TextView;

public class MainActivity extends Activity {

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

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

        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        myThread.handler.sendEmptyMessage(2);
    }
}

import android.os.Handler;
import android.os.Looper;
import android.os.Message;

public class MyThread extends Thread{

    Handler handler;

    @Override
    public void run() {

        Looper.prepare();

        handler=new Handler(){

            @Override
            public void handleMessage(Message msg) {
                switch (msg.what) {
                case 1:
                    System.out.println("主线程向子线程发送了消息:1");
                    break;
                case 2:
                    System.out.println("主线程向子线程发送了消息:2");
                    break;
                default:
                    break;
                }
            }
        };

        Looper.loop();
    }
}
    原文作者:Android源码分析
    原文地址: https://blog.csdn.net/yano_nankai/article/details/49201229
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞