Android音讯机制介绍

Android音讯机制中的四大概念:

  • ThreadLocal:当前线程存储的数据仅能从当前线程取出。
  • MessageQueue:具有时刻优先级的音讯行列。
  • Looper:轮询音讯行列,看是否有新的音讯到来。
  • Handler:具体处理逻辑的地方。

过程:

  1. 预备工作:创立Handler,如果是在子线程中创立,还需要调用Looper#prepare(),在Handler的结构函数中,会绑定其间的LooperMessageQueue
  2. 发送音讯:创立音讯,运用Handler发送。
  3. 进入MessageQueue:由于Handler中绑定着音讯行列,所以Message很自然的被放进音讯行列。
  4. Looper轮询音讯行列:Looper是一个死循环,一直观察有没有新的音讯到来,之后从Message取出绑定的Handler,最后调用Handler中的处理逻辑,这一切都发生在Looper循环的线程,这也是Handler能够在指定线程处理任务的原因。

伪代码描述的Android主线程音讯处理流程,这样会看得更明晰易懂:

// 1. 创立Handler实例,关联主线程的Looper
Handler mainHandler = new Handler(Looper.getMainLooper());
// 2. 界说音讯处理逻辑
void handleMessage(Message msg) {
    int what = msg.what; // 获取音讯的what特点,表明音讯类型
    Object obj = msg.obj; // 获取音讯的obj特点,携带的额外数据
    // 依据音讯类型履行相应的操作
    switch (what) {
        case MESSAGE_TYPE_ONE:
            // 处理第一种类型的音讯
            break;
        case MESSAGE_TYPE_TWO:
            // 处理第二种类型的音讯
            break;
        // ...其他case处理不同的音讯类型
        default:
            // 默认处理逻辑
            break;
    }
}
// 3. 发送音讯到音讯行列
Message msg = obtainMessage(MESSAGE_TYPE_ONE); // 创立一个新音讯,并设置类型
mainHandler.sendMessage(msg); // 发送音讯到主线程的音讯行列
// 4. Handler在主线程的Looper循环中处理音讯
while (true) { // Looper的循环体
    Message msg = mainHandler.getLooper().getMessageQueue().next(); // 从音讯行列中取出一个音讯
    if (msg == null) {
        break; // 如果音讯行列为空,退出循环,而且App进程会完毕
    }
    handleMessage(msg); // 调用handleMessage办法处理音讯
}
// 5. 音讯处理完成
// handleMessage办法中的代码会依据音讯类型履行相应的逻辑

Android中为什么主线程不会由于Looper.loop()里的死循环卡死?

Android中为什么主线程不会由于Looper.loop()里的死循环卡死? – Gityuan的回答 – 知乎 www.zhihu.com/question/34…

简略的总结来说:主线程也不过是运行在运用进程里面的,但实际上对于CPU来说这些进程,线程,都是一片片代码块,按照指令去履行,死循环的规划为了确保主线程能够一直存活,不会在运行一段时刻后主动退出,这样App就不会无故完毕掉了,而真实导致主线程卡死的操作是在回调办法如onCreateonStartonResume等中履行时刻过长。这些长时刻的操作会导致界面掉帧,乃至触发运用程序无响应 ANR。然而,Looper.loop()自身并不会导致运用卡死。当没有音讯需要处理时,主线程会休眠,等候新音讯的到来,不会过多占用CPU资源。


子线程必定不能更新ui么?什么时候能够?什么时候不能够。

子线程更新UI的规则:

不能够

  • 直接从子线程调用UI组件的办法,如TextView.setText()Button.setEnabled()等,这些都是不允许的。
  • 在子线程中直接操作布局或者视图层次结构也是不允许的。

能够

  • 经过Handler将音讯发送到主线程的音讯行列中,然后在主线程的Handler中处理音讯并更新UI。
  • 运用AsyncTask类,它允许在后台线程中履行耗时操作,然后在完成时将成果发布到主线程以更新UI。
  • 运用LiveDataViewModel,这些是Android架构组件的一部分,它们能够在后台线程中进行数据加载,然后在主线程中观察和更新UI。
  • 运用runOnUiThread()办法,这是Activity类的一个办法,它允许你将一个Runnable目标发布到主线程的音讯行列中,并在主线程中履行。

Activity的生命周期是怎么完成在死循环体外能够履行起来的?

实际上Activity的生命周期还是是经过Android的音讯机制和Handler来完成的,依托主线程的Looper.loop,当收到不同Message时则选用相应措施;比方收到msg=H.LAUNCH_ACTIVITY,则调用ActivityThread.handleLaunchActivity()办法,终究会经过反射机制,创立Activity实例,然后再履行Activity.onCreate()等办法;再比方收到msg=H.PAUSE_ACTIVITY,则调用ActivityThread.handlePauseActivity()办法,终究会履行Activity.onPause()等办法。

结合简略流程图和看以下的伪代码,你就更明晰的知道,Activity生命周期和Handle之间的一些纤细联系,还有AMS在其间所做的一些处理:

Android 面试| Android的Handle音讯机制

// 伪代码表明的Android体系类和办法
class ActivityThread {
    private Looper mainLooper;
    private Handler mainHandler;
    // 初始化主线程的Looper和Handler
    function initLooperAndHandler() {
        mainLooper = Looper.prepareMainLooper();
        mainHandler = new Handler(mainLooper) {
            override function handleMessage(Message msg) {
                // 依据音讯的内容履行不同的生命周期操作
                switch (msg.what) {
                    case MSG_START_ACTIVITY:
                        startActivity(msg.obj); // msg.obj包含Activity的相关信息
                        break;
                    case MSG_RESUME_ACTIVITY:
                        resumeActivity(id); // id是Activity的标识
                        break;
                    case MSG_PAUSE_ACTIVITY:
                        pauseActivity(id);
                        break;
                    case MSG_STOP_ACTIVITY:
                        stopActivity(id);
                        break;
                    case MSG_DESTROY_ACTIVITY:
                        destroyActivity(id);
                        break;
                    // 其他音讯处理...
                }
            }
        }
    }
    // 启动Activity
    function startActivity(activityInfo) {
        // 创立Activity实例并调用onCreate等生命周期办法
        activity = createActivityInstance(activityInfo)
        activity.onCreate()
        // ...
    }
    // 恢复Activity
    function resumeActivity(id) {
        activity = findActivityById(id)
        activity.onResume()
        // ...
    }
    // 暂停Activity
    function pauseActivity(id) {
        activity = findActivityById(id)
        activity.onPause()
        // ...
    }
    // 停止Activity
    function stopActivity(id) {
        activity = findActivityById(id)
        activity.onStop()
        // ...
    }
    // 毁掉Activity
    function destroyActivity(id) {
        activity = findActivityById(id)
        activity.onDestroy()
        // ...
    }
}
// 在Application的onCreate办法中初始化ActivityThread
ActivityThread.mainThread.initLooperAndHandler();
// 伪代码表明的Activity类
class Activity {
    // 重写生命周期回调办法
    function onCreate() {
        // 初始化UI和数据
    }
    function onStart() {
        // Activity开端变得可见
    }
    function onResume() {
        // Activity预备交互
    }
    function onPause() {
        // Activity暂停,不再交互
    }
    function onStop() {
        // Activity不再可见
    }
    function onDestroy() {
        // 整理资源,Activity即将被毁掉
    }
}
// 伪代码表明的AMS( Activity Manager Service )发送音讯给ActivityThread
class AMS {
    function sendMessageToActivityThread(msg) {
        // 经过Binder IPC机制发送音讯到ActivityThread的主线程Handler
        ActivityThread.mainHandler.sendMessage(msg);
    }
}
// AMS依据不同的事件向ActivityThread发送音讯
AMS.sendMessageToActivityThread(MSG_START_ACTIVITY);
AMS.sendMessageToActivityThread(MSG_RESUME_ACTIVITY);
AMS.sendMessageToActivityThread(MSG_PAUSE_ACTIVITY);
AMS.sendMessageToActivityThread(MSG_STOP_ACTIVITY);
AMS.sendMessageToActivityThread(MSG_DESTROY_ACTIVITY);

以后每两天之内更新一道Android常见的面试题,以自己的角度去通俗简略易懂方式去说,不深化源码但讲基本原理,以伪代码为中心;如果你比较想问什么问题,能够评论。