天天看点

Android深入理解:Handler + Looper + MessageHandler + Looper + Message:生产者 + 消费者 + 仓库(任务队列)1.Handler(生产者add)2.HandlerThread3.IntentService4.Looper(消费者get and deal)5.Message(任务,产品)(Intent, Runnable, Message)6.MessageQueue(任务队列,产品池)7.应用案例

声明:本文是一篇对Handler相关内容的整理(经过相当一段时间,几次内容增减),有相当部分内容来源网络,其中融入部分作者本身的理解,并加以整理。如有涉及到哪位老师的原作,在此深表感谢!

目录

目录

Handler + Looper + Message:生产者 + 消费者 + 仓库(任务队列)

1.Handler(生产者add)

1.1.Handler创建对象

1.2.Handler发送消息

1.3.Handler处理消息

1.4.Handler移除消息

2.HandlerThread

2.1.定义:

2.2.适用场景:

2.3.源码:

2.4.DEMO:

3.IntentService

3.1.定义:

3.2.源码:

3.3.DEMO:

3.3.1.多文件下载:

3.3.2.广播更新UI:

3.4.总结:

4.Looper(消费者get and deal)

4.1.定义:

4.2.机制:

4.3.应用:

1.ActivityThread

2.ActivityThread响应消息

3.ApplicationThread

4.IApplicationThread

5.App启动流程

4.4.quit:

5.Message(任务,产品)(Intent, Runnable, Message)

5.1.定义:

5.2.关键属性:

5.3.构造方式:

6.MessageQueue(任务队列,产品池)

6.1.定义:

7.应用案例

7.1.子线程发消息给子线程

7.2.主线程发消息给子线程

7.3.子线程发消息给主线程

7.4.AsyncTask

Handler + Looper + Message:生产者 + 消费者 + 仓库(任务队列)

作者浅见。

Handler和Looper是多对一的关系,Looper和MessageQueue是一对一的关系。一个线程中,只有一个Looper 和 MessageQueue,但可以有多个Handler。Handler发送消息时,本身作为关联的target存入消息,Looper获取消息时,最终调用消息关联的Handler进行处理。

1.Handler(生产者add)

Handler:线程间通讯机制,是由Looper和MessageQueue来构建消息机制的。Handler发送消息给MessageQueue,并处理Looper分发过来的消息。

线程间通讯:

Handler在某线程把Message或者Runnable发送到目标线程的MessageQueue,然后由目标线程Looper对MessageQueue循环调度,再召唤发送消息的Handler进行处理。这个时候,处理过程:

@Override

public void handleMessage(Message msg) {
    super.handleMessage(msg);
}
           

将在Looper所属线程(目标线程)执行,即完成线程切换。

1.1.Handler创建对象

每个Handler对象都会绑定一个Looper对象,每个Looper对象对应一个消息队列(MessageQueue)。如果在创建Handler时不指定与其绑定的Looper对象,系统默认会将当前线程的Looper绑定到该Handler上。

在主线程中(系统会为主线程自动创建Looper对象,开启消息循环)可以直接使用new Handler() 创建Handler对象,自动与主线程的Looper对象绑定。

new Handler() 等价于new Handler(Looper.myLooper())。Looper.myLooper():获取当前进程的looper对象,类似的 Looper.getMainLooper() 用于获取主线程的Looper对象。

在非主线程中直接这样创建Handler则会报错,因为Android系统默认情况下非主线程中没有开启Looper,而Handler对象必须绑定Looper对象。这种情况下,需先在该线程中手动开启Looper(Looper.prepare()-->Looper.loop()),然后将其绑定到Handler对象上;或者通过Looper.getMainLooper(),获得主线程的Looper,将其绑定到此Handler对象上。

创建Handler对象,还可以通过传入Callback接口类型方式创建。

public Handler(Callback callback) {
    this(callback, false);
}
public interface Callback {
    public boolean handleMessage(Message msg);
}
           

1.2.Handler发送消息

Handler发送的消息都会加入到Looper的MessageQueue中。Handler只有一个消息队列,即MessageQueue。

关于:

handler.post(new Runnable() {
      @Override
      public void run() {
                        
      }
});
           

通过post()传进去的Runnable对象将会被封装成消息对象后传入MessageQueue;使用Handler.sendMessage()将消息对象直接加入到消息队列中。

使用post()将Runnable对象放到消息队列中后,当Looper轮循到该Runnable执行时,实际上并不会单独开启一个新线程,而仍然在当前Looper绑定的线程中执行,Looper只是调用了该线程对象的run()而已。如,在子线程中定义了更新UI的指令,若直接开启将该线程执行,则会报错;而通过post()将其加入到主线程的Looper中并执行,就可以实现UI的更新。

使用sendMessage()将消息对象加入到消息队列后,当Looper轮询到该消息时,就会调用Handler的handleMessage()来对其进行处理。再以更新UI为例,使用这种方法的话,就先将主线程的Looper绑定在Handler对象上,重载handleMessage()来处理UI更新,然后向其发送消息就可以了。

如果Handler对象与其调用者在同一线程中,如果在Handler的消息处理方法中设置了延时操作,则调用线程也会堵塞,因为Looper轮循是线性的,所以Handler处理Message的过程也是线性的。

1.3.Handler处理消息

Handler 在处理消息时,会有三种情况:

if :msg.callback 不为空

这在使用 Handler.postXXX(Runnable) 发送消息的时候会发生,直接调用 Runnable 的 run() 方法。

else if :mCallback 不为空

如果构造Handler时候以 Handler.Callback 为参数构造 Handler 时会发生,CallBack接口方法作为消息处理方法替代Handler.handleMessage() 执行处理操作。

Handler handler = new Handler(new Handler.Callback() {

    @Override
    public boolean handleMessage(Message message) {
        return false;
    }
});
           

else :最后就调用 Handler.handleMessage() 方法

需要我们在 Handler 子类里重写

1.4.Handler移除消息

public final void removeCallbacks(Runnable r){

    mQueue.removeMessages(this, r, null);

}

public final void removeMessages(int what) {

    mQueue.removeMessages(this, what, null);

}
           

2.HandlerThread

2.1.定义:

HandlerThread 是一个包含 Looper 的 Thread,我们可以直接使用这个 Looper 创建 Handler。避免在子线程中对Looper手动繁琐的操作(Looper.prepare() ——> Looper.loop()),让我们可以直接在线程中使用 Handler 来处理异步任务。

HandlerThread 本身是一个Thread,需要start()启动。

HandlerThread 在run() 方法中为本线程创建了Looper(Looper.prepare()),调用 onLooperPrepared 后开启了循环(Looper.loop())

HandlerThread 需要在子类中重写 onLooperPrepared,做Looper启动前的初始化工作

HandlerThread 可以指定优先级,注意这里的参数是 Process.XXX 而不是 Thread.XXX

HandlerThread = Thread + Looper,适合在子线程中执行耗时的、可能有多个任务的操作的场景,比如说多个网络请求操作,或者多文件 I/O 等等。

2.2.适用场景:

为某个任务 / 回调单独开启线程,并提供由Handler + Looper提供任务(Message)调度机制。

个人理解:HandlerThread是一个可以通过Looper + Message 实现在子线程(Looper 和 MessageQueue在子线程,所以Looper循环消息,触发消息处理方法也是在子线程)中依次循环执行任务的线程类。

2.3.源码:

public class HandlerThread extends Thread {
    int mPriority;
    int mTid = -1;
    Looper mLooper;
    private @Nullable Handler mHandler;
    public HandlerThread(String name) {
        super(name);
        mPriority = Process.THREAD_PRIORITY_DEFAULT;
    }
    /**
     * Constructs a HandlerThread.
     * @param name
     * @param priority The priority to run the thread at. The value supplied must be from 
     * {@link android.os.Process} and not from java.lang.Thread.
     */
    public HandlerThread(String name, int priority) {
        super(name);
        mPriority = priority;
    }
    /**
     * 子类需要重写的方法,在这里做一些执行前的初始化工作
     * Call back method that can be explicitly overridden if needed to execute some
     * setup before Looper loops.
     */
    protected void onLooperPrepared() {
    }
    //调用 start() 后就会执行的 run()
    @Override
    public void run() {
        mTid = Process.myTid();
	//创建了 Looepr
        Looper.prepare();
        synchronized (this) {
            mLooper = Looper.myLooper();
            notifyAll();//Looper 已经创建,唤醒阻塞在获取 Looper 的线程
        }
        Process.setThreadPriority(mPriority);
        onLooperPrepared();
        Looper.loop();//开始循环
        mTid = -1;
    }
    /**
     * 获取当前线程的 Looper
     * 如果线程不是正常运行的就返回 null
     * 如果线程启动后,Looper 还没创建,就 wait() 等待 创建 Looper 后 notify
     * This method returns the Looper associated with this thread. If this thread not been started
     * or for any reason isAlive() returns false, this method will return null. If this thread
     * has been started, this method will block until the looper has been initialized.  
     * @return The 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;
    }
    /**
     * @return a shared {@link Handler} associated with this thread
     * @hide
     */
    @NonNull
    public Handler getThreadHandler() {
        if (mHandler == null) {
            mHandler = new Handler(getLooper());
        }
        return mHandler;
    }
    /**
     * Quits the handler thread's looper.
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     *
     * @see #quitSafely
     */
    public boolean quit() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quit();
            return true;
        }
        return false;
    }
    /**
     * Quits the handler thread's looper safely.
     * @return True if the looper looper has been asked to quit or false if the
     * thread had not yet started running.
     */
    public boolean quitSafely() {
        Looper looper = getLooper();
        if (looper != null) {
            looper.quitSafely();
            return true;
        }
        return false;
    }
    /**
     * Returns the identifier of this thread. See Process.myTid().
     */
    public int getThreadId() {
        return mTid;
    }
}
           

2.4.DEMO:

使用 HandlerThread 实现子线程完成多个下载任务。

DownloadThread,它有两个 Handler 类型的成员变量,一个是用于在子线程传递、执行任务,另一个用于外部传入,在主线程显示下载状态:

public class DownloadThread extends HandlerThread implements Handler.Callback {
    private final String KEY_URL = "url";
    public static final int TYPE_START = 1;
    public static final int TYPE_FINISHED = 2;
    /**
     * 外部传入,通知主线程显示下载状态
     */
    private Handler mUIHandler;
    /**
     * 内部创建,子线程传递、执行任务
     */
    private Handler mWorkerHandler;
    /**
     * download list
     */
    private List<String> mDownloadUrlList;
    public DownloadThread(final String name) {
        super(name);
    }
    /**
     * 执行初始化任务
     */
    @Override
    protected void onLooperPrepared() {
        super.onLooperPrepared();
        mWorkerHandler = new Handler(getLooper(), this);
        if (mUIHandler == null) {
            throw new IllegalArgumentException("No UIHandler!");
        }
        // 将接收到的任务消息挨个添加到消息队列中
        for (String url : mDownloadUrlList) {
            Message message = mWorkerHandler.obtainMessage();
            Bundle bundle = new Bundle();
            bundle.putString(KEY_URL, url);
            message.setData(bundle);
            mWorkerHandler.sendMessage(message);
        }
    }
    public void setDownloadUrls(String... urls) {
        mDownloadUrlList = Arrays.asList(urls);
    }
    /**
     * 获取主线程 Handler
     */
    public Handler getUIHandler() {
        return mUIHandler;
    }
    /**
     * 注入主线程 Handler
     */
    public DownloadThread setUIHandler(final Handler UIHandler) {
        mUIHandler = UIHandler;
        return this;
    }
    /**
     * 子线程中执行任务,完成后发送消息到主线程
     */
    @Override
    public boolean handleMessage(final Message msg) {
        if (msg == null || msg.getData() == null) {
            return false;
        }
        String url = (String) msg.getData().get(KEY_URL);
        //下载开始,通知主线程
        Message startMsg = mUIHandler.obtainMessage(TYPE_START, "\n 开始下载 @" + url);
        mUIHandler.sendMessage(startMsg);
        SystemClock.sleep(2000);    //模拟下载
        //下载完成,通知主线程
        Message finishMsg = mUIHandler.obtainMessage(TYPE_FINISHED, "\n 下载完成 @" + url);
        mUIHandler.sendMessage(finishMsg);
        return true;
    }
    @Override
    public boolean quitSafely() {
        mUIHandler = null;
        return super.quitSafely();
    }
}
           

创建一个子线程 mWorkerHandler,在 onLooperPrepared()中初始化 Handler,使用的是 HandlerThread 创建的 Looper 。同时将外部传入的下载 url 以 Message 的方式发送到子线程中的 MessageQueue 中。

当调用 DownloadThread.start() 时,子线程中的 Looper 开始工作,会按顺序取出消息队列中的队列处理,然后调用子线程的 Handler 处理(handleMessage()),在这个方法中进行耗时任务,然后通过 mUIHandler 将下载状态信息传递到主线程

在外部Activity(Fragment)实现Hander.Callback接口,调用:

mUIHandler = new Handler(this);
mDownloadThread = new DownloadThread("下载线程");
mDownloadThread.setUIHandler(mUIHandler);
mDownloadThread.setDownloadUrls("http://pan.baidu.com/s/1qYc3EDQ",
        "http://bbs.005.tv/thread-589833-1-1.html", 
        "http://list.youku.com/show/id_zc51e1d547a5b11e2a19e.html?");
mDownloadThread.start();
           

同时在Activiy的onDestroy()方法中退出下载线程:

mDownloadThread.quitSafely();
           

3.IntentService

3.1.定义:

IntentService 是一个抽象类,本身是一个Service,同时又在内部创建了一个HandlerThread 。IntentService 使用工作线程逐一处理所有启动请求。如果你不需要在 Service 中执行并发任务,IntentService 是最好的选择。

3.2.源码:

public abstract class IntentService extends Service {
    private volatile Looper mServiceLooper;
    private volatile ServiceHandler mServiceHandler;
    private String mName;
    private boolean mRedelivery;
    //内部创建的 Handler
    private final class ServiceHandler extends Handler {
        public ServiceHandler(Looper looper) {
            super(looper);
        }
        @Override
        public void handleMessage(Message msg) {
            //调用这个方法处理数据
            onHandleIntent((Intent) msg.obj);
            //处理完Service就自尽了
            stopSelf(msg.arg1);
        }
    }
    //子类需要重写的构造函数,参数是服务的名称
    public IntentService(String name) {
        super();
        mName = name;
    }
    //设置当前服务被意外关闭后是否重新启动
    //如果设置为 true,onStartCommand() 方法将返回 Service.START_REDELIVER_INTENT,这样当
    //当前进程在 onHandleIntent() 方法返回前销毁时,会重启进程,重新使用之前的 Intent 启动这个服务
    //(如果有多个 Intent,只会使用最后的一个)
    //如果设置为 false,onStartCommand() 方法返回 Service.START_NOT_STICKY,当进程销毁后也不重启服务
    public void setIntentRedelivery(boolean enabled) {
        mRedelivery = enabled;
    }
    @Override
    public void onCreate() {
        super.onCreate();
        //创建时启动一个 HandlerThread
        HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
        thread.start();
        //拿到 HandlerThread 中的 Looper,然后创建一个子线程中的 Handler
        mServiceLooper = thread.getLooper();
        mServiceHandler = new ServiceHandler(mServiceLooper);
    }
    @Override
    public void onStart(@Nullable Intent intent, int startId) {
        //将 intent 和 startId 以消息的形式发送到 Handler
        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();    //值得学习的,在销毁时退出 Looper
    }
    @Override
    @Nullable
    public IBinder onBind(Intent intent) {
        return null;
    }
    @WorkerThread
    protected abstract void onHandleIntent(@Nullable Intent intent);
}
           

源代码做了以下几件事情:

(1)创建了一个 HandlerThread 默认的工作线程

(2)使用 HandlerThread 的 Looper 创建了一个 Handler,这个 Handler 执行在子线程

(3)在 onStartCommand() 中调用 onStart(),然后在 onStart() 中将 intent 和 startId 以消息的形式发送到 Handler

(4)在 Handler 中将消息队列中的 Intent 按顺序传递给 onHandleIntent() 

(5)在处理完所有启动请求后自动停止服务,不需要我们调用 stopSelf()

可以看到在 handleMessage 方法中只调用了一次onHandleIntent() 之后就调用 stopSelf() 了,那么说,该Handler只能执行一个任务么?

非也!stopSelf() 方法传递了一个 id,这个 id 是启动服务时 IActivityManager 分配的 id,当我们调用 stopSelf(id) 方法结束服务时,IActivityManager 会对比当前 id 是否为最新启动该服务的 id,如果是就关闭服务。子线程中onHandleIntent方法经历了耗时操作,当本次stopSelf(id)调用之前,很可能onStartCommand会多次调用,每次调用都会生成新的启动id,所以本次stopSelf传入的id,很可能已经不是最新启动服务的id了。

因此只有当最后一次启动 IntentService 的任务执行完毕才会关闭这个服务。

注意:只有onHandleIntent方法是执行在子线程的,因为处理消息的looper是子线程HandlerThread提供的looper。其余方法均在主线程运行。

由于最终每个任务的处理都会调用 onHandleIntent(),因此使用 IntentService 也很简单,只需实现 onHandleIntent() 方法,在这里执行对应的后台工作即可。

3.3.DEMO:

3.3.1.多文件下载:

/**
 * Description:使用 IntentService 实现下载
 */
public class DownloadService extends IntentService {
    private static final String TAG = "DownloadService";
    public static final String DOWNLOAD_URL = "down_load_url";
    public static final int WHAT_DOWNLOAD_FINISHED = 1;
    public static final int WHAT_DOWNLOAD_STARTED = 2;
    public DownloadService() {
        super(TAG);
    }
    private static Handler mUIHandler;
    public static void setUIHandler(final Handler UIHandler) {
        mUIHandler = UIHandler;
    }
    /**
     * 这个方法运行在子线程
     *
     * @param intent
     */
    @Override
    protected void onHandleIntent(final Intent intent) {
        String url = intent.getStringExtra(DOWNLOAD_URL);
        if (!TextUtils.isEmpty(url)) {
            sendMessageToMainThread(WHAT_DOWNLOAD_STARTED, "\n " + DateUtils.getCurrentTime() + " 开始下载任务:\n" + url);
            try {
                Bitmap bitmap = downloadUrlToBitmap(url);
                SystemClock.sleep(1000);    //延迟一秒发送消息
                sendMessageToMainThread(WHAT_DOWNLOAD_FINISHED, bitmap);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    /**
     * 发送消息到主线程
     *
     * @param id
     * @param o
     */
    private void sendMessageToMainThread(final int id, final Object o) {
        if (mUIHandler != null) {
            mUIHandler.sendMessage(mUIHandler.obtainMessage(id, o));
        }
    }
    /**
     * 下载图片
     *
     * @param url
     * @return
     * @throws Exception
     */
    private Bitmap downloadUrlToBitmap(String url) throws Exception {
        HttpURLConnection urlConnection = (HttpURLConnection) new URL(url).openConnection();
        BufferedInputStream in = new BufferedInputStream(urlConnection.getInputStream(), 8 * 1024);
        Bitmap bitmap = BitmapFactory.decodeStream(in);
        urlConnection.disconnect();
        in.close();
        return bitmap;
    }
}
           

主线程调用:

public void downloadImage() {
    DownloadService.setUIHandler(new Handler(this));
    Intent intent = new Intent(this, DownloadService.class);
    for (String url : urlList) {
        intent.putExtra(DownloadService.DOWNLOAD_URL, url);
        startService(intent);
    }
    mBtnDownload.setEnabled(false);
}
           

(1)设置 UI 线程的 Handler 给 IntentService

(2)使用 startService(intent) 启动 IntentService 执行图片下载任务

(3)在 Handler 的 handleMessage 中根据消息类型进行相应处理

在第一次启动 IntentService 后,IntentService 仍然可以接受新的请求,接受到的新的请求被放入了工作队列中,等待被串行执行。

3.3.2.广播更新UI:

public class MyIntentService extends IntentService {
    /**
     * 是否正在运行
     */
    private boolean isRunning;
    /**
     *进度
     */
    private int count;
    /**
     * 广播
     */
    private LocalBroadcastManager mLocalBroadcastManager;
    public MyIntentService() {
        super("MyIntentService");
        Logout.e("MyIntentService");
    }
    @Override
    public void onCreate() {
        super.onCreate();
        Logout.e("onCreate");
        mLocalBroadcastManager = LocalBroadcastManager.getInstance(this);
    }
    @Override
    protected void onHandleIntent(Intent intent) {
        Logout.e("onHandleIntent");
        try {
            Thread.sleep(1000);
            isRunning = true;
            count = 0;
            while (isRunning) {
                count++;
                if (count >= 100) {
                    isRunning = false;
                }
                Thread.sleep(50);
                sendThreadStatus("线程运行中...", count);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    /**
     * 发送进度消息
     */
    private void sendThreadStatus(String status, int progress) {
        Intent intent = new Intent(IntentServiceActivity.ACTION_TYPE_THREAD);
        intent.putExtra("status", status);
        intent.putExtra("progress", progress);
        mLocalBroadcastManager.sendBroadcast(intent);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        Logout.e("线程结束运行..." + count);
    }
}
           

3.4.总结:

IntentService是一个串行执行异步任务、会自尽的 Service,优先级比较高,在后台不会轻易被系统杀死;它可以接收多个 Intent 请求,然后在子线程中按顺序执行。

适合于执行由UI触发的处理多任务的后台Service任务,并可以把后台任务执行的情况通过一定的机制反馈给UI。

IntentService,在onHandlerIntent()的回调里面来处理塞到IntentService的任务。所以IntentService就不仅仅具备了异步线程的特性,还同时保留了Service不受主页面生命周期影响的特点。我们可以在IntentService里面通过设置闹钟间隔性的触发异步任务,例如刷新数据,更新缓存的图片等。

首先,因为IntentService内置的是HandlerThread作为异步线程,所以每一个交给IntentService的任务都将以队列的方式逐个被执行到,一旦队列中有某个任务执行时间过长,那么就会导致后续的任务都会被延迟处理。

其次,通常使用到IntentService的时候,我们会结合使用BroadcastReceiver把工作线程的任务执行结果返回给主UI线程。使用广播容易引起性能问题,我们可以使用LocalBroadcastManager来发送只在程序内部传递的广播,从而提升广播的性能。我们也可以使用runOnUiThread()快速回调到主UI线程。

最后,包含正在运行的IntentService的程序相比起纯粹的后台程序更不容易被系统杀死,该程序的优先级是介于前台程序与纯后台程序之间的。

4.Looper(消费者get and deal)

4.1.定义:

消息循环管理器。每个线程只有一个Looper,负责管理MessageQueue, 以无限循环的方式去查找MessageQueue中是否有新消息。如果有,MessageQueue中取出消息,并将消息分给对应的Handler处理;如果没有就standby(等待)。一个线程创建Handler时首先需要创建Looper的,不然报错:RuntimeException: No Looper; Looper.prepare() wasn't called on this thread,而且每个线程下只能创建一个Looper,不然会报错:RuntimeException: Only one Looper may be created per thread。

4.2.机制:

线程中默认没有 Looper,我们需要调用 Looper.prepare() 方法为当前线程创建一个 Looper,调用Looper.loop()来使消息循环起作用,使用Looper.prepare()和Looper.loop()就可以让消息处理在当前线程(主线程默认开启,不需要手动调用)中完成。

Looper.loop()之后,进入无限循环:

for (;;) {    //无限循环模式
    Message msg = queue.next(); //从消息队列中读取消息,可能会阻塞
    if (msg == null) {    //当消息队列中没有消息时就会返回,不过这只发生在 queue 退出的时候
        return;
    }
    //...
    try {
        msg.target.dispatchMessage(msg);    //调用消息关联的 Handler 处理消息
    } finally {
        if (traceTag != 0) {
            Trace.traceEnd(traceTag);
        }
    }
    //...
    msg.recycleUnchecked();    //标记这个消息被回收
}
           

可以看到,loop()其实是调用 MessageQueue.next() 方法取消息,如果没有消息的话会阻塞,直到有新的消息进入或者消息队列退出。

拿到消息后Looper 并没有执行消息,而是调用消息关联的 Handler (target)处理消息,真正执行消息的还是添加消息到队列中的那个 Handler。

所以应该说Looper属于哪个线程的,消息处理就在哪个线程执行!!!

4.3.应用:

首先,Android 本身是由事件驱动的,在主线程中…… looper.loop() 不断地接收事件、处理事件。四大组件的调度、输入事件、绘制请求、每一个点击触摸或者说Activity的生命周期都是运行在 Looper.loop() 的控制之下,如果它停止了,应用也就停止了。

只能是UI线程中某一个消息或者说对消息的处理阻塞了 Looper.loop(),而不能是 Looper.loop() 阻塞UI线程。也可以理解为,UI线程中执行的代码其实是执行在looper.loop()的循环周期中。

主线程同一时间只能处理一个 Message,所以,如果UI线程中某个消息处理时间过长(点击事件业务处理操作),那么下一次的消息比如用户的点击事件不能处理了,整个循环就会产生卡顿,时间一长就成了ANR。

UI线程的消息处理机制(系统级)(简单分析):

特别参考:https://blog.csdn.net/hzwailll/article/details/85339714

1.ActivityThread

ActivityThread通过 ApplicationThread 与 AMS(ActivityManagerService) 进行进程通信

(1)ActivityThread可以代表App主线程(UI线程),但是ActivityThread并不是一个Thread,严格意义来讲,ActivityThread是初始化App进程的类,它的main() 方法是App进程初始化的入口。

也就是说,ActivityThread初始化了App进程,同时ActivityThread将作为App的初始线程,App进程内所有线程都是由这个初始线程启动的。但是ActivityThread初始化App进程的代码(main入口),其实是在一个实际存在的Main线程中被调用执行的。

所以ActivityThread可以代表App的主线程(UI线程,即初始线程),但是App真实的主线程是隐藏起来不可见的Main线程。

1,ActivityThread.main()

main() 方法主要做了以下几件事情:

public static void main(String[] args) {

//....
    //创建Looper和MessageQueue对象,用于处理主线程的消息
    Looper.prepareMainLooper();
    //创建ActivityThread对象
    ActivityThread thread = new ActivityThread();
    //建立Binder通道 (创建新线程)  在attach方法中会完成Application对象的初始化,然后调用Application的onCreate()方法
    thread.attach(false);
    if (sMainThreadHandler == null) {

     sMainThreadHandler = thread.getHandler();

}

Looper.loop(); //消息循环运行
    throw new RuntimeException("Main thread loop unexpectedly exited");
}
           

2,Looper.prepareMainLooper()

主线程Looper初始化

/主线程Looper的初始化

public static void prepareMainLooper() {
    prepare(false);
    synchronized (Looper.class) {
        if (sMainLooper != null) {
            throw new IllegalStateException("The main Looper has already been prepared.");
        }
        sMainLooper = myLooper();
    }
}
//普通线程Looper的初始化
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));
}
           

quitAllowed:标记Looper是否允许退出,当调用quit方法时会判断该参数,如果false,抛出异常。主线程(ActivityThread)Looper不允许退出;普通线程Looper允许退出。

sMainLooper:承载主线程(ActivityThread)唯一Looper对象,并通过Looper.getMainLooper()对外提供对象访问。

3,sMainThreadHandler

if (sMainThreadHandler == null) {

     sMainThreadHandler = thread.getHandler();

}
           

获取ActivityThread的Handler,在ActivityThread中,Handler作为final类型的成员变量在ActivityThread创建对象的时候被初始化

//ActivityThread的成员变量

final H mH = new H();

so …… 主线程(ActivityThread)的初始化它的main方法中,在此之前main首先对MainLooper进行了初始化,主线程的Handler创建时机是在ActivityThread初始化的时候。

4,ApplicationThread及Activity的创建和启动

ApplicationThread被定义为ActivityThread的私有内部类,实现了IBinder接口,用于ActivityThread和ActivityManagerService所在进程的进程间通讯。

final ApplicationThread mAppThread = new ApplicationThread();
           

ActivityThread的main方法调用了thread.attach(false); attach中将mAppThread 作为参数传入ActivityManagerService:

final IActivityManager mgr = ActivityManager.getService();

try {
    mgr.attachApplication(mAppThread);
} catch (RemoteException ex) {
    throw ex.rethrowFromSystemServer();
} else {
        ...
}
           

即把ApplicationThread在远程服务AMS进行注册绑定,后续由AMS管理ActivityThread所有生命周期。

接下来,AMS 在attachApplication中做了两件事:

(1)创建Application

AMS. attachApplication()方法中:通过mAppThread调用ApplicationThread的bindApplication 用于创建Application。该方法会向ActivityThread发送BIND_APPLICATION消息,最终的处理方法是调用Application.onCreate()。

ApplicationThread中的bindApplication方法

public final void bindApplication(...) {

    // ...
    sendMessage(H.BIND_APPLICATION, data);
    // ...
}
           

ActivityThread中的handleBindApplication方法

private void handleBindApplication(AppBindData data) {

    // ...
    try {
        Application app = data.info.makeApplication(data.restrictedBackupMode, null);
        mInitialApplication = app;
        // ...
        try {
            mInstrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
        }
    } finally {
    }
}
           

LoadedApk中的方法,用于创建Application

public Application makeApplication(boolean forceDefaultAppClass, Instrumentation instrumentation) {

    // 如果存在Application的实例,则直接返回,这也说明Application是个单例
    if (mApplication != null) {
        return mApplication;
    }
    Application app = null;
    // 这里通过反射初始化Application
    // ...
    if (instrumentation != null) {
        try {
            //调用Application的onCreate方法
            instrumentation.callApplicationOnCreate(app);
        } catch (Exception e) {
        }
    }
    return app;
}
           

(2)创建Activity

AMS. attachApplication()方法中:通过mStackSupervisor.attachApplicationLocked(app)创建Activity,mStackSupervisor是AMS的成员变量,为Activity堆栈管理辅助类实例,该方法最终会调用ApplicationThread类的scheduleLaunchActivity方法,该方法也是类似于第一步,向ActivityThread的消息队列发送创建Activity的消息,最终在ActivityThread中完成创建Activity的操作。

(3)总结:

ActivityThread.main ——> 初始化Main Looper ——> create ActivityThead ——> 注册ApplicationThread到AMS ——> AMS通过mAppThread创建Application(ApplicationThread. bindApplication() 和 ActivityThread通过Handler + Message + Looper实现)——> AMS通过mAppThread创建Activity(ApplicationThread. scheduleLaunchActivity () 和 ActivityThread通过Handler + Message + Looper实现)——> Looper.loop()(开启消息循环,调度执行上述操作)

Application.onCreate() 永远早于任何一个Activity.onCreate()

2.ActivityThread响应消息

ActivityThread的内部类 H 继承于Handler,Activity的生命周期都是依靠ActivityThread的Looper.loop,当H 收到不同Message时则采用相应措施:

System_Server:通过ApplicationThreadProxy通过Binder调用ApplicationThread的 scheduleXXX系列方法

ApplicationThread:Handler跨线程发消息给ActivityThread

ActivityThread :sendMessage  ->  handleMessage  ->  handleXXXActivvity  ->  performXXXActivity。

(1)ActivityThread.H

public final class ActivityThread {

    // ... 
    final H mH = new H();
    private class H extends Handler {
        // ...声明的一些常量
        public void handleMessage(Message msg) {
            // ...
            switch (msg.what) {
                // 针对不同的常量,做不同的业务处理
                case LAUNCH_ACTIVITY: {
                    // ...启动一个Activity
                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                    // ...
                }
                break;
                case RELAUNCH_ACTIVITY: {
                    //...
                    handleRelaunchActivity(r);
                    // ...
                }
                break;
                case PAUSE_ACTIVITY: {
                    // ...
                    handlePauseActivity((IBinder) args.arg1, false,
                            (args.argi1 & USER_LEAVING) != 0, args.argi2,
                            (args.argi1 & DONT_REPORT) != 0, args.argi3);
                    maybeSnapshot();
                    // ...
                }
                break;
                // ...
            }
            // ...
        }
        private void maybeSnapshot() {
            //...这个方法主要统计snapshot
        }
    }
}
           

H 主要作用就是根据不同的情况处理各种业务,而且处理业务的方法一般是以handle开头,handleXXX的格式:

handleActivityConfigurationChanged()

handleBindApplication()
handleBindService()
handleCancelVisibleBehind()
handleConfigurationChanged()
handleCreateService()
handleDestroyActivity()
handleDispatchPackageBroadcast()
handleLaunchActivity()
handleLowMemory()
handleMessage()
handleNewIntent()
handlePauseActivity()
handleReceiver()
handleRelaunchActivity()
handleResumeActivity()
handleSendResult()
handleServiceArgs()
handleStopActivity()
handleStopService()
           

上述方法有的又会调用到如下的performXXX系列方法完成最终的事件处理:

performDestroyActivity()

performDestroyActivity()
performLaunchActivity()
performNewIntents()
performPauseActivity()
performPauseActivity()
performRestartActivity()
performResumeActivity()
performStopActivity()
performStopActivityInner()
performUserLeavingActivity()
           

当msg.what == LAUNCH_ACTIVITY就是调用handleLaunchActivity方法启动一个Activity,在handleLaunchActivity中又调用了performLaunchActivity方法来创建一个Activity实例,完成Activity的启动。 handleLaunchActivity源码如下:

(2)案例一:启动一个Activity

当msg.what == LAUNCH_ACTIVITY就是调用handleLaunchActivity方法启动一个Activity,在handleLaunchActivity中又调用了performLaunchActivity方法来创建一个Activity实例,完成Activity的启动。 handleLaunchActivity源码如下:

private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {

    //...调用performLaunchActivity方法完成Activity的启动
    Activity a = performLaunchActivity(r, customIntent);
    //...
}
           

(3)案例二:栈顶Activity的onPause过程

ActivityStack.startPausingLocked()

IApplicationThread.schedulePauseActivity()
ActivityThread.sendMessage()
ActivityThread.H.sendMessage();
ActivityThread.H.handleMessage()
ActivityThread.handlePauseActivity()
ActivityThread.performPauseActivity()
Activity.performPause()
Activity.onPause()
           

3.ApplicationThread

Android深入理解:Handler + Looper + MessageHandler + Looper + Message:生产者 + 消费者 + 仓库(任务队列)1.Handler(生产者add)2.HandlerThread3.IntentService4.Looper(消费者get and deal)5.Message(任务,产品)(Intent, Runnable, Message)6.MessageQueue(任务队列,产品池)7.应用案例

ApplicationThread和启动Application有关!

ApplicationThread是ActivityThread的内部类,继承ApplicationThreadNative,也是一个Binder对象。ApplicationThread内部定义了一系列scheduleXXX方法,这些方法由其外部类ActivityThread的Binder远程代理对象(ApplicationThreadProxy)调用,之后通过Handler发出相应消息给 H 来处理。

在此处它是作为server端等待client端的请求然后进行处理,最大的client就是AMS。

private class ApplicationThread extends ApplicationThreadNative {

    //...
    schedulePauseActivity()
    scheduleStopActivity()
    scheduleResumeActivity()
    scheduleSendResult()
    scheduleLaunchActivity()
    scheduleNewIntent()
    scheduleDestroyActivity()
    scheduleReceiver()
    scheduleCreateService()
    scheduleBindService()
    scheduleUnbindService()
    scheduleServiceArgs()
    scheduleStopService()
    bindApplication()
    scheduleConfigurationChanged()
    scheduleRegisteredReceiver()
    scheduleInstallProvider()
}
           

4.IApplicationThread

定义了一系列业务通讯接口方法:

public interface IApplicationThread extends IInterface {

    void schedulePauseActivity() throws RemoteException;
    void scheduleStopActivity() throws RemoteException;
    void scheduleWindowVisibility(IBinder token, boolean showWindow) throws RemoteException;
    void scheduleSleeping() throws RemoteException;
    void scheduleResumeActivity() throws RemoteException;
    void scheduleSendResult(IBinder token, List<ResultInfo> results) throws RemoteException;
    void scheduleLaunchActivity() throws RemoteException;
    void scheduleRelaunchActivity() throws RemoteException;
    void scheduleNewIntent() throws RemoteException;
    void scheduleReceiver() throws RemoteException;
    void scheduleCreateBackupAgent() throws RemoteException;
    void scheduleDestroyBackupAgent()throws RemoteException;
    void scheduleCreateService() throws RemoteException;
    void scheduleBindService() throws RemoteException;
    void scheduleUnbindService() throws RemoteException;
    void scheduleServiceArgs() throws RemoteException;
    void scheduleStopService() throws RemoteException;
    void bindApplication() throws RemoteException;
    void scheduleExit() throws RemoteException;
    void scheduleSuicide() throws RemoteException;
    void scheduleConfigurationChanged() throws RemoteException;
    //...
}
           

5.App启动流程

安卓系统启动流程:

加载BootLoader --> 初始化Kernel --> 启动init进程(加载1000多个.class文件) --> init进程fork出Zygote进程 --> Zygote进程fork出SystemServer进程 --> 启动所有系统Service

说明:

(1)当ActivityManagerService、PackageManagerService、WindowManagerService启动之后,系统开始启动Launcher;

(2)SystemServer:系统进程,负责管理系统服务

(3)ActivityManagerServices(AMS):是一个服务端对象,负责所有的Activity的生命周期,AMS通过Binder与Activity通信,而AMS与Zygote之间是通过Socket通信

(4)ActivityThread:App主线程,它的main()方法是APP的真正入口

(5)ApplicationThread:一个实现了IBinder接口的ActivityThread私有内部类,负责ActivityThread和AMS进程间通信

App启动流程:

Android深入理解:Handler + Looper + MessageHandler + Looper + Message:生产者 + 消费者 + 仓库(任务队列)1.Handler(生产者add)2.HandlerThread3.IntentService4.Looper(消费者get and deal)5.Message(任务,产品)(Intent, Runnable, Message)6.MessageQueue(任务队列,产品池)7.应用案例

(1)点击桌面应用图标 ——> Launcher通过Binder发送startActivity给system_server进程中的AMS,发送启动请求

(2)AMS通过Socket请求Zygote孵化App进程

(3)Zygote fork出App进程,并执行ActivityThread的main方法,初始化主线程Looper,创建ActivityThread线程,初始化主线程Handler,初始化ApplicationThread用于和AMS通信交互

(4)ActivityThread通过Binder向AMS发起attachApplication请求,这里实际上就是APP进程通过Binder调用sytem_server进程中AMS的attachApplication方法,将ApplicationThread对象与AMS绑定

(5)接下来,AMS通过Binder IPC向App进程发送bindApplication请求(实际调用了ApplicationThread的bindApplication,此时ApplicationThread通过Handler发送BIND_APPLICATION消息给ActivityThread),由ActivityThread完成初始化Application的操作:Application.onCreate()

(6)接下来,AMS通过Binder IPC向App进程发送scheduleLaunchActivity请求(实际调用了ApplicationThread的scheduleLaunchActivity,此时ApplicationThread通过Handler发送LAUNCH_ACTIVITY消息给ActivityThread),由ActivityThread通过反射机制,创建目标Activity并回调Activity.onCreate()

注意AMS和主线程并不直接通信,而是AMS和主线程的内部类ApplicationThread通过Binder通信,ApplicationThread再和主线程通过Handler消息交互。

到此,App便正式启动,开始进入Activity生命周期,执行完onCreate/onStart/onResume方法,UI渲染后显示APP主界面。

4.4.quit:

Looper开启loop()之后,必须保证结束quit(),quitSafely()!!!

Looper 两种结束方式的区别:

(1)quit():

立即回收链表中所有消息,并且禁止后续消息入队列。在停止后如果 Handler 还发送消息,会返回 false,表示入队失败,所以这个方法是不安全的。

(2)quitSafely():

将还未执行的消息回收掉,后续进入队列的消息将不会被处理,同时标记消息队列为退出状态。Handler.sendMessage 也会返回 false。当消息队列被标记位退出状态时,它的 next() 方法会返回 null,于是 Looper.loop() 循环就结束了。

5.Message(任务,产品)(Intent, Runnable, Message)

5.1.定义:

Message可以承载任意类型的对象和描述信息,可以被发送给 Handler。

5.2.关键属性:

(1)public int what;                 // 用来标识一个消息,接收消息方可以根据/它知道这个消息是做什么的

(2)public int arg1;

         public int arg2;                  // 数据载体:int 型

(3)public Object obj;              // 数据载体: 对象型

(4)Bundle data;    // 数据载体:复杂对象

(5)Handler target; // 发送和处理消息关联的 Handler

(6)private static final Object sPoolSync = new Object();

(7)private static Message sPool; // 回收消息链表

(8)private static int sPoolSize = 0;

5.3.构造方式:

new Message();

Message.obtain();  推荐

Handler.obtainMessage();   推荐

推荐使用后两个,会从一个消息回收池里获取消息,而不是新建一个,这样可以节省内存。原理:如果 sPool (回收消息链表)存在就从复用消息链表头部取一个消息,然后重置它的标志位;如果不存在复用消息链表就新建一个消息。

一个消息在被 Looper 处理时或者移出队列时会被标识为 FLAG_IN_USE,然后会被加入回收的消息链表,这样我们调用 Message.obtain() 方法时就可以从回收的消息池中获取一个旧的消息,从而节约成本。

6.MessageQueue(任务队列,产品池)

6.1.定义:

MessageQueue(先进先出):消息队列,管理着一个 Message 的列表,Handlers 为它添加消息,Looper 从中取消息。。虽然名为队列,但事实上它的内部存储结构并不是真正的队列,而是采用单链表的数据结构来存储消息列表的,其中主要有插入enqueue()和从中拿走并删除next()两个方法。

7.应用案例

写在Looper.loop()之后的代码不会被立即执行,这个函数内部是一个循环,当调用后mHandler.getLooper().quit()后,loop才会中止,其后的代码才能得以运行。

警惕线程未终止造成的内存泄露;譬如在Activity中关联了一个生命周期超过Activity的Thread,在退出Activity时切记结束线程。一个典型的例子就是HandlerThread的run方法是一个死循环,它不会自己结束,线程的生命周期超过了Activity生命周期,我们必须手动在Activity的销毁方法中中调运thread.getLooper().quit();才不会泄露。

另外,注意不要在任何子线程持有 UI 组件或者 Activity 的引用。

7.1.子线程发消息给子线程

class TestThread extends Thread{
    @Override
    public void run() {
        super.run();
        // prepare MessageQueue and looper
        Looper.prepare();
        Handler handler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
// deal message……
            }
        };
handler.sendMessage(new Message())
        // start looper
        Looper.loop();
    }
}
           

7.2.主线程发消息给子线程

(1)子线程中创建持有子线程Looper的Handler

(2)主线程使用子线程中Handler发送消息,最终在子线程的Handler中执行。

7.3.子线程发消息给主线程

方案一:子线程中创建持有主线程Looper的Handler,由该Handler在子线程发送消息到主线程的MessageQueue,并由该Handler在主线程执行。

          Handler handler = new Handler(getMainLooper());

方案二:子线程持有主线程创建的Handler对象,并由该Handler在子线程发送消息到主线程的MessageQueue,并由该Handler在主线程执行。

7.4.AsyncTask

默认情况下,所有的AsyncTask任务都是被线性调度执行的,他们处在同一个任务队列当中,按顺序逐个执行。假设你按照顺序启动20个AsyncTask,一旦其中的某个AsyncTask执行时间过长,队列中的其他剩余AsyncTask都处于阻塞状态,必须等到该任务执行完毕之后才能够有机会执行下一个任务。

为了解决线性队列等待的问题,我们可以使用AsyncTask.executeOnExecutor()强制指定AsyncTask使用线程池并发调度任务。

使用AsyncTask很容易导致内存泄漏,一旦把AsyncTask写成Activity的内部类的形式就很容易因为AsyncTask生命周期的不确定而导致Activity发生泄漏。

继续阅读