Android Handler源码分析

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

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

Handler消息模型


这里写图片描述

Looper类


这里写图片描述


主要成员变量和方法:

    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对象。消息的处理函数不是必须的。


这里写图片描述


这里写图片描述

简单的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();
    }
}
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值