Handler机制

本文深入解析Android中的Handler机制,包括Looper、MessageQueue的工作原理,以及主线程与子线程中Handler的使用方式。探讨了HandlerThread和IntentService的实现细节,展示了如何在不同线程间传递消息。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 每个线程只有一个looper,一个消息队列。MessageQueue是 Looper 的内部类,被 Looper 持有。MessageQueue是个单链表结构,便于增删。

2. 主线程会提供好looper对象,直接使用handler的无参构造即可;子线程中要自己准备looper对象,并开启消息循环;
    子线程中推荐使用ThreadHandler,它继承自Thread,并准备好了Looper对象。使用handler的有参构造,传入HandlerThread准备的Looper对象。此时虽然主线程创建了Handler,但是处理消息是在子线程中的。因为looper对象在子线程中。

3. 主线程和HandlerThread子线程都会提供好looper,主线程中创建handler对象时,直接使用无参构造即可。handlermessage方法运行在主线程中,和looper在同一个线程中 
    子线程中创建handler对象,要使用有参的构造,把HandlerThread的looper传入。handlermessage方法运行在子线程中
    耗时任务,则用handerThread,会执行在子线程中

4. 1个线程,可能有n个handle,多个线程会有N*N个handler。怎么找到自己的looper的?hander在创建对象时,会和当前线程的looper关联。looper也能看到mq。消息内有个msg.target方法关联了当前handler,也知道找哪个handler的handlermessage方法。 

5. Android的主线程是ActivityThread。TreadLocal:同一个对象,不同线程可以有不同的副本。

1 Handler机制--线程间通信的方式

子线程调用Handler对象的sendMessge方法发送消息给MessageQueue,而和Handler对象绑定的Looper对象,会通过loop方法从MessageQueue中获取消息,交由Handler对象的handleMessge方法处理,进行更新UI等操作。Looper对象运行在主线程,和Looper对象绑定的Handler的handleMessge方法也运行在主线程,这样消息就从子线程来到了主线程,实现了线程间的通信。

2. 如何理解Looper和Handler的绑定关系

Handler对象在创建时,会绑定一个Looper对象。
Handler对象的handleMessage方法和该Looper对象运行在同一线程中。
Handler对象和它绑定的Looper对象不一定运行在同一线程中。

1)在当前线程中创建Handler时,会调用Looper.myLooper()方法,获取当前线程的Looper对象,并有mLooper保存。

    public Handler() {
        this(null, false);
    }

    public Handler(Callback callback, boolean async) {
        if (FIND_POTENTIAL_LEAKS) {
            final Class<? extends Handler> klass = getClass();
            if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
                    (klass.getModifiers() & Modifier.STATIC) == 0) {
                Log.w(TAG, "The following Handler class should be static or leaks might occur: " +
                    klass.getCanonicalName());
            }
        }

        mLooper = Looper.myLooper();//会调用当前线程的Looper。若是主线程,会默认创建Looper;若是子线程,要自己创建Looper,否则会报错。
        if (mLooper == null) {
            throw new RuntimeException(
                "Can't create handler inside thread that has not called Looper.prepare()");
        }
        mQueue = mLooper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

2)主线程中,创建Handler对象时调用Handler的无参构造即可,因为主线程会默认提供好Looper对象,主线程的入口是ActivityThread的main方法:

    public static void main(String[] args) {//frameworks/base/core/java/android/app
        ......
     
        //创建Looper和MessageQueue对象,用于处理主线程的消息
        Looper.prepareMainLooper();
     
        //创建ActivityThread对象   
        ActivityThread thread = new ActivityThread();
     
        //建立Binder通道 (创建新线程)
        thread.attach(false);
        mAnrAppManager.setMessageLogger(Looper.myLooper());
     
        //消息循环运行
        Looper.loop();
     
        throw new RuntimeException("Main thread loop unexpectedly exited");
    }


3)子线程中,调用Handler的无参构造,此时也会给mLooper赋值,但自己并未创建Looper对象,Looper.myLooper()获取为空,紧接着就会抛出异常。
此时要自己手动创建Looper对象,并开启消息循环。

class LooperThread extends Thread {
    public Handler mHandler;

      public void run() {
          Looper.prepare();//创建Looper对象

          mHandler = new Handler() {
              public void handleMessage(Message msg) {
                  // 这里处理消息
              }
          };
          Looper.loop();//开启无线循环
      }
}

4) 子线程中,上述创建handle对象的方式过于繁琐,就提供了HandlerThread。HandlerThread继承自Thread,内部创建了Looper。此时创建的Handler对象,传入HandlerThread的Looper对象,且Looper对象运行在子线程中,则Handler的handlemessage方法和Looper对象一样,也运行在子线程中。

HandlerThread 的使用例子

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

    private HandlerThread handlerThread;//子线程
    private Handler mWorkHandler;//子线程Handler

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

        //创建子线程handlerThread
        handlerThread = new HandlerThread("work_thread");
        //启动子线程:创建子线程的Looper对象
        handlerThread.start();

        //利用子线程的Looper对象,创建子线程的Handler,同时传入回调接口
        mWorkHandler = new Handler(handlerThread.getLooper(), new MyCallBack());

        Log.e(TAG, "mWorkHandler will send msg from main thread");
        mWorkHandler.sendEmptyMessage(1);
    }

    //该callback运行于子线程
    class MyCallBack implements Handler.Callback{
        @Override
        public boolean handleMessage(Message msg) {
            Log.e(TAG, "MyCallBack's handleMessage is in " + Thread.currentThread().getName());
            mUIHandler.sendEmptyMessage(msg.what);
            return true;
        }
    }

    private Handler mUIHandler = new Handler(){//主线程Handler
        @Override
        public void handleMessage(Message msg) {
            Log.e(TAG, "mUIHandler's handleMessage is in " + Thread.currentThread().getName());
        }
    };

    @Override
    protected void onDestroy() {
        //停止handlerThread
        handlerThread.quit();
        super.onDestroy();
    }
}

结合源码 分析:  在创建HandlerThread对象后必须调用其start()方法才能进行其他操作,而调用start()方法后相当于启动了子线程,会执行HandlerThread的run()方法

    @Override
    public void run() {
        mTid = Process.myTid();
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();
        mTid = -1;
    }

run方法中执行了Looper.prepare()代码,这时子线程的Looper对象将被创建,当Looper对象被创建后将和当前线程HandlerThread绑定。这样我们才可以在创建Handler对象时,使用Looper对象,进而确保Handler对象中的handleMessage方法是在子线程执行的。

handlerThread.getLooper()获取Looper对象:

        public Looper getLooper() {
            if (!isAlive()) {
                return null;
            }
            // If the thread has been started, wait until the looper has been created.
            synchronized (this) {
                while (isAlive() && mLooper == null) {
                    try {
                        wait();//等待被唤醒
                    } catch (InterruptedException e) {
                    }
                }
            }
            return mLooper;
        }

通过getLooper方法获取looper对象时,会先先判断当前线程是否启动了,如果线程已经启动,那么将会进入同步语句并判断Looper是否为null,为null则代表Looper对象还没有被赋值,也就是还没被创建,此时当前调用线程进入等待阶段,直到Looper对象被创建,并在启动子线程的run()方法内调用notifyAll()方法唤醒等待的主线程,最后才返回Looper对象。

之所以需要等待唤醒机制,是因为Looper的创建是在子线程HandlerThread中执行的,而调用getLooper方法则是在主线程进行的,这样我们就无法保障我们在调用getLooper方法时Looper已经被创建,到这里我们也就明白了在获取mLooper对象时会存在一个同步的问题,只有当线程创建成功并且Looper对象也创建成功之后才能获得mLooper的值,HandlerThread内部则通过等待唤醒机制解决了同步问题。

此时创建Handler对象,最终会调用

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

当MyCallBack的对象传给mCallBack后,会在mWorkHandler的dispatchMessage方法中,调用MyCallBack的handleMessage方法处理消息。此时,mWorkHandler内没有重写handleMessage方法,而使用CallBack接口的handleMessage方法来处理消息。

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

退出该Activity时,调用子线程HandleThread的quit方法

5) intentService继承自Service ,intentService内部使用HandlerThread开启了子线程,用于处理耗时任务,执行完毕后,会调用stopSelf方法停止服务。

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;

    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }

        @Override
        public void handleMessage(Message msg) {
            onHandleIntent((Intent)msg.obj);
            stopSelf(msg.arg1);
        }
    }

    /**
     * Creates an IntentService.  Invoked by your subclass's constructor.
     *
     * @param name Used to name the worker thread, important only for debugging.
     */
    public IntentService(String name) {
        super();
        mName = name;
    }

    ......

    @Override
    public void onCreate() {
        // TODO: It would be nice to have an option to hold a partial wakelock
        // during processing, and to have a static startService(Context, Intent)
        // method that would launch the service & hand off a wakelock.

        super.onCreate();
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();

        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }

    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        Message msg = mServiceHandler.obtainMessage();
        msg.arg1 = startId;
        msg.obj = intent;
        mServiceHandler.sendMessage(msg);
    }

    /**
     * You should not override this method for your IntentService. Instead,
     * override {@link #onHandleIntent}, which the system calls when the IntentService
     * receives a start request.
     * @see android.app.Service#onStartCommand
     */
    @Override
    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {
        onStart(intent, startId);
        return mRedelivery ? START_REDELIVER_INTENT : START_NOT_STICKY;
    }

    @Override
    public void onDestroy() {
        mServiceLooper.quit();
    }

    /**
     * Unless you provide binding for your service, you don't need to implement this
     * method, because the default implementation returns null.
     * @see android.app.Service#onBind
     */
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }

    /**
     * This method is invoked on the worker thread with a request to process.
     * Only one Intent is processed at a time, but the processing happens on a
     * worker thread that runs independently from other application logic.
     * So, if this code takes a long time, it will hold up other requests to
     * the same IntentService, but it will not hold up anything else.
     * When all requests have been handled, the IntentService stops itself,
     * so you should not call {@link #stopSelf}.
     *
     * @param intent The value passed to {@link
     *               android.content.Context#startService(Intent)}.
     *               This may be null if the service is being restarted after
     *               its process has gone away; see
     *               {@link android.app.Service#onStartCommand}
     *               for details.
     */
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}

在onCreate方法中,调用了HandleThread的构造创建了子线程thread,用于执行耗时任务。获取到了该线程的Looper对象后,传入了ServiceHandler,ServiceHandler是继承自Handler,此时重写了handlerMessage方法。

与4)不同,此时创建Handler对象时调用了

    public Handler(Looper looper) { 
        this(looper, null, false); 
    }

    public Handler(Looper looper, Callback callback, boolean async) {
        mLooper = looper;
        mQueue = looper.mQueue;
        mCallback = callback;
        mAsynchronous = async;
    }

此时mCallback为null,最后处理消息的是自定义handler时重写的handlerMessage方法,此时handlerMessage方法调用了onHandleIntent方法,且onHandleIntent方法是一个抽象方法,当我们在使用IntentServcie时,要重写onHandleIntent方法,执行具体的耗时任务。

当创建HandlerThread对象时,使用到了mName成员,而mName是从IntentService的有参构造中传过来的,故,在使用IntentService时要使用其有参构造,传入子线程的名字。

6)AsyncTask的底层也是使用了Handler机制:AsyncTask源码分析

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值