Android主线程简介

当Android应用程序启动后,系统会创建一个叫做“main”的线程。它就是主线程,也叫UI线程,非常重要。 在Android系统中,主线程主要负责执行四大组件的执行。负责分发事件给构建,包括绘制事件。
Android中规定访问UI只能在主线程进行,如果在子线程中访问UI,那么程序就会抛出异常。ViewRootImpl中对UI的操作进行了验证,由它的checkThread()方法来完成的。代码如下:
    void checkThread() {        if (mThread != Thread.currentThread()) {            throw new CalledFromWrongThreadException(                    "Only the original thread that created a view hierarchy can touch its views.");        }    }
那么为什么安卓系统不允许在子线程中访问UI呢?这是因为Android的UI控件不是线程安全的,如果在多线程中并发访问可能会导致UI控件处于不可预期的状态。如果在UI控件的访问加上锁机制的话,由于锁机制会阻塞线程的执行, 会降低UI访问的效率
主线程的主要责任:
1、快速的处理UI事件。Android希望UI线程能快速响应用户操作,如果UI线程花太多时间处理后台的工作,会让用户有非常糟糕的体验。当UI事件发生时,让用户等待时间超过5秒而未处理,Android系统就会给用户显示ANR提示信息。 2、快速的处理Broadcast消息。在BroadcastReceiver的onReceive()函数中,不宜占用太长的时间,否则会导致主线程无法处理其它的Broadcast消息或UI事件。如果占用时间超过10秒, Android系统就会给用户显示ANR提示信息。
所以当有比较耗时的任务时,我们需要在子线程执行,当有需要操作UI界面的才通过Handler,回调到主线程中修改UI界面。关于Handler的知识点,可以看一下我的另一篇博客:Handler消息机制。

Android主线程的消息机制

Android的主线程就是ActivityThread,主线程的入口方法和Java类一样,是main方法。下面我们来看一下: /frameworks/base/core/java/android/app/ActivityThread.java
    public static void main(String[] args) {        ...        Looper.prepareMainLooper();        ActivityThread thread = new ActivityThread();        thread.attach(false);        if (sMainThreadHandler == null) {            sMainThreadHandler = thread.getHandler();        }        if (false) {            Looper.myLooper().setMessageLogging(new                    LogPrinter(Log.DEBUG, "ActivityThread"));        }        // End of event ActivityThreadMain.        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);        Looper.loop();        throw new RuntimeException("Main thread loop unexpectedly exited");    }
首先Looper.prepareMainLooper()方法创建主线程的Looper,而MessageQueue在Looper的构造函数中创建。而最后通过Looper.loop()来开启消息循环。通过Handler消息机制我们了解到,loop中是一个无限循环。而thread.getHandler()获取主线程中H类的对象mH。H继承于Handler。我们来看看H类的定义。 /frameworks/base/core/java/android/app/ActivityThread.java
    private class H extends Handler {        public static final int LAUNCH_ACTIVITY         = 100;        public static final int PAUSE_ACTIVITY          = 101;        public static final int PAUSE_ACTIVITY_FINISHING= 102;        public static final int STOP_ACTIVITY_SHOW      = 103;        public static final int STOP_ACTIVITY_HIDE      = 104;        public static final int SHOW_WINDOW             = 105;        public static final int HIDE_WINDOW             = 106;        public static final int RESUME_ACTIVITY         = 107;        ...        public void handleMessage(Message msg) {            if (DEBUG_MESSAGES) Slog.v(TAG, ">>> handling: " + codeToString(msg.what));            switch (msg.what) {                case LAUNCH_ACTIVITY: {                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStart");                    final ActivityClientRecord r = (ActivityClientRecord) msg.obj;                    r.packageInfo = getPackageInfoNoCheck(                            r.activityInfo.applicationInfo, r.compatInfo);                    handleLaunchActivity(r, null);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                } break;                case RELAUNCH_ACTIVITY: {                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityRestart");                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;                    handleRelaunchActivity(r);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                } break;                case PAUSE_ACTIVITY:                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");                    handlePauseActivity((IBinder)msg.obj, false, (msg.arg1&1) != 0, msg.arg2,                            (msg.arg1&2) != 0);                    maybeSnapshot();                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    break;                case PAUSE_ACTIVITY_FINISHING:                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityPause");                    handlePauseActivity((IBinder)msg.obj, true, (msg.arg1&1) != 0, msg.arg2,                            (msg.arg1&1) != 0);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    break;                case STOP_ACTIVITY_SHOW:                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");                    handleStopActivity((IBinder)msg.obj, true, msg.arg2);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    break;                case STOP_ACTIVITY_HIDE:                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityStop");                    handleStopActivity((IBinder)msg.obj, false, msg.arg2);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    break;                case SHOW_WINDOW:                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityShowWindow");                    handleWindowVisibility((IBinder)msg.obj, true);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    break;                case HIDE_WINDOW:                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityHideWindow");                    handleWindowVisibility((IBinder)msg.obj, false);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    break;                case RESUME_ACTIVITY:                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");                    handleResumeActivity((IBinder) msg.obj, true, msg.arg1 != 0, true);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    break;                case SEND_RESULT:                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDeliverResult");                    handleSendResult((ResultData)msg.obj);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    break;                case DESTROY_ACTIVITY:                    Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityDestroy");                    handleDestroyActivity((IBinder)msg.obj, msg.arg1 != 0,                            msg.arg2, false);                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);                    break;                ...            }            if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));        }        ...    }
通过H的定义,我们可以看到四大组件的启动和停止过程。
在之前思考过一个问题,UI线程中使用了Looper,那么它为什么没有阻塞。 现在我们可以知道答案了,UI主线程同样是以消息驱动执行的,所有的四大组件的生命周期都是通过消息来驱动执行的。当MessageQueue中没有消息的时候,next()就会阻塞在那里,导致主线程阻塞,只是这个时候用户没有任何操作界面静止,我们感觉不到而已。当一个新的消息到来,next立即将这个消息返回给loop。我们再通过mH回调到主线程中处理。若这个时候消息处理的时间过长,就会影响UI线程的刷新速率,造成卡顿的现象。

更多相关文章

  1. Android异步机制一:使用Thread+Handler实现非UI线程更新UI界面
  2. android 多任务多线程断点下载
  3. [Android]Thread线程入门3--多线程
  4. Android消息通知-Notification
  5. 【Android】Android的消息机制
  6. android的消息处理机制

随机推荐

  1. android 上下左右手势判断 根据别人的改
  2. android listView
  3. Android复习(十)
  4. Android核心基础(四)
  5. Android(安卓)封装http请求的工具类
  6. android 監聽系統屬性變化的方法
  7. Android常用的工具类-收藏用
  8. Android(安卓)单位
  9. Android使用HttpURLConnection提交数据
  10. android 定时发送短信