Android ActivityThread(主线程或UI线程)简介

原创 2013年11月06日 10:56:47

1. ActivityThread功能

    它管理应用进程的主线程的执行(相当于普通Java程序的main入口函数),并根据AMS的要求(通过IApplicationThread接口,AMS为Client、ActivityThread.ApplicationThread为Server)负责调度和执行activities、broadcasts和其它操作。

    在Android系统中,在默认情况下,一个应用程序内的各个组件(如Activity、BroadcastReceiver、Service)都会在同一个进程(Process)里执行,且由此进程的【主线程】负责执行。

    在Android系统中,如果有特别指定(通过android:process),也可以让特定组件在不同的进程中运行。无论组件在哪一个进程中运行,默认情况下,他们都由此进程的【主线程】负责执行。

    【主线程】既要处理Activity组件的UI事件,又要处理Service后台服务工作,通常会忙不过来。为了解决此问题,主线程可以创建多个子线程来处理后台服务工作,而本身专心处理UI画面的事件。

     【主线程】的主要责任:

       • 快速处理UI事件。而且只有它才处理UI事件, 其它线程还不能存取UI画面上的对象(如TextView等),此时, 主线程就叫做UI线程。基本上,Android希望UI线程能根据用户的要求做出快速响应,如果UI线程花太多时间处理后台的工作,当UI事件发生时,让用户等待时间超过5秒而未处理,Android系统就会给用户显示ANR提示信息。

         只有UI线程才能执行View派生类的onDraw()函数。

      • 快速处理Broadcast消息。【主线程】除了处理UI事件之外,还要处理Broadcast消息。所以在BroadcastReceiver的onReceive()函数中,不宜占用太长的时间,否则导致【主线程】无法处理其它的Broadcast消息或UI事件。如果占用时间超过10秒, Android系统就会给用户显示ANR提示信息。

      注意事项:

      • 尽量避免让【主线程】执行耗时的操作,让它能快速处理UI事件和Broadcast消息。

      • BroadcastReceiver的子类都是无状态的,即每次启动时,才会创建其对象,然后调用它的onReceive()函数,当执行完onReceive()函数时,就立即删除此对象。由于每次调用其函数时,会重新创建一个新的对象,所以对象里的属性值,是无法让各函数所共享。   

1.1 Thread与SurfaceView

      View组件由UI线程(主线程)所执行。如果需要迅速更新UI画面或UI画图需要较长时间,则需要使用SurfaceView。它可由后台线程(background thread)来执行,而View只能由UI(主)线程执行。SurfaceView内有高效的rendering机制,可以让后台线程快速刷新Surface的内容。

      View ---> UI(主)线程

      SurfaceView ---> 后台线程   


2. Android应用程序主线程stack

    在一个只有Activity派生类的应用程序中,它包含如下线程:


    main线程stack如下:

  at android.os.MessageQueue.nativePollOnce(Native Method)	
  at android.os.MessageQueue.next(MessageQueue.java:118)	
  at android.os.Looper.loop(Looper.java:118)	
  
  at android.app.ActivityThread.main(ActivityThread.java:4424)	// Java main入口函数
  
  at java.lang.reflect.Method.invokeNative(Native Method)	
  at java.lang.reflect.Method.invoke(Method.java:511)	
  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)	
  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)	
  at dalvik.system.NativeStart.main(Native Method)	

     JDWP线程stack如下:

  at org.apache.harmony.dalvik.ddmc.DdmVmInternal.getStackTraceById(Native Method)	
  at android.ddm.DdmHandleThread.handleSTKL(DdmHandleThread.java:131)	
  at android.ddm.DdmHandleThread.handleChunk(DdmHandleThread.java:77)	
  at org.apache.harmony.dalvik.ddmc.DdmServer.dispatch(DdmServer.java:171)	
  at dalvik.system.NativeStart.run(Native Method)	

3. IApplicationThread关系图



4. ActivityThread类

   ActivityThread类即代表Application主线程。

4.1 类中关键信息

/**
 * This manages the execution of the main thread in an
 * application process, scheduling and executing activities,
 * broadcasts, and other operations on it as the activity
 * manager requests.
 *
 * {@hide}
 */
public final class ActivityThread {

    static ContextImpl mSystemContext = null;

    static IPackageManager sPackageManager;
    
    // 创建ApplicationThread实例,以接收AMS指令并执行
    final ApplicationThread mAppThread = new ApplicationThread();

    final Looper mLooper = Looper.myLooper();

    final H mH = new H();

    final HashMap<IBinder, ActivityClientRecord> mActivities
            = new HashMap<IBinder, ActivityClientRecord>();
    
    // List of new activities (via ActivityRecord.nextIdle) that should
    // be reported when next we idle.
    ActivityClientRecord mNewActivities = null;
    
    // Number of activities that are currently visible on-screen.
    int mNumVisibleActivities = 0;
    
    final HashMap<IBinder, Service> mServices
            = new HashMap<IBinder, Service>();
    
    Application mInitialApplication;

    final ArrayList<Application> mAllApplications
            = new ArrayList<Application>();

    static final ThreadLocal<ActivityThread> sThreadLocal = new ThreadLocal<ActivityThread>();
    Instrumentation mInstrumentation;

    static Handler sMainThreadHandler;  // set once in main()

    static final class ActivityClientRecord {
        IBinder token;
        int ident;
        Intent intent;
        Bundle state;
        Activity activity;
        Window window;
        Activity parent;
        String embeddedID;
        Activity.NonConfigurationInstances lastNonConfigurationInstances;
        boolean paused;
        boolean stopped;
        boolean hideForNow;
        Configuration newConfig;
        Configuration createdConfig;
        ActivityClientRecord nextIdle;

        String profileFile;
        ParcelFileDescriptor profileFd;
        boolean autoStopProfiler;

        ActivityInfo activityInfo;
        CompatibilityInfo compatInfo;
        LoadedApk packageInfo; //包信息,通过调用ActivityThread.getPapckageInfo而获得

        List<ResultInfo> pendingResults;
        List<Intent> pendingIntents;

        boolean startsNotResumed;
        boolean isForward;
        int pendingConfigChanges;
        boolean onlyLocalRequest;

        View mPendingRemoveWindow;
        WindowManager mPendingRemoveWindowManager;

        ...
    }


    private class ApplicationThread extends ApplicationThreadNative {

        private void updatePendingConfiguration(Configuration config) {
            synchronized (mPackages) {
                if (mPendingConfiguration == null ||
                        mPendingConfiguration.isOtherSeqNewer(config)) {
                    mPendingConfiguration = config;
                }
            }
        }

        public final void schedulePauseActivity(IBinder token, boolean finished,
                boolean userLeaving, int configChanges) {
            queueOrSendMessage(
                    finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,
                    token,
                    (userLeaving ? 1 : 0),
                    configChanges);
        }

        // we use token to identify this activity without having to send the
        // activity itself back to the activity manager. (matters more with ipc)
        public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
                ActivityInfo info, Configuration curConfig, CompatibilityInfo compatInfo,
                Bundle state, List<ResultInfo> pendingResults,
                List<Intent> pendingNewIntents, boolean notResumed, boolean isForward,
                String profileName, ParcelFileDescriptor profileFd, boolean autoStopProfiler) {
            ActivityClientRecord r = new ActivityClientRecord();

            r.token = token;
            r.ident = ident;
            r.intent = intent;
            r.activityInfo = info;
            r.compatInfo = compatInfo;
            r.state = state;

            r.pendingResults = pendingResults;
            r.pendingIntents = pendingNewIntents;

            r.startsNotResumed = notResumed;
            r.isForward = isForward;

            r.profileFile = profileName;
            r.profileFd = profileFd;
            r.autoStopProfiler = autoStopProfiler;

            updatePendingConfiguration(curConfig);

            queueOrSendMessage(H.LAUNCH_ACTIVITY, r);
        }

        ...
    }

    private class H extends Handler {

        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");
                    ActivityClientRecord r = (ActivityClientRecord)msg.obj;

                    r.packageInfo = getPackageInfoNoCheck(
                            r.activityInfo.applicationInfo, r.compatInfo);
                    handleLaunchActivity(r, null);
                    Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                } break;
                ...
            }
            if (DEBUG_MESSAGES) Slog.v(TAG, "<<< done: " + codeToString(msg.what));
        }
       
        ...
    }

    public static ActivityThread currentActivityThread() {
        return sThreadLocal.get();
    }

 
    public static void main(String[] args) {
        SamplingProfilerIntegration.start();

        // CloseGuard defaults to true and can be quite spammy.  We
        // disable it here, but selectively enable it later (via
        // StrictMode) on debug builds, but using DropBox, not logs.
        CloseGuard.setEnabled(false);

        Environment.initForCurrentUser();

        // Set the reporter for event logging in libcore
        EventLogger.setReporter(new EventLoggingReporter());

        Process.setArgV0("<pre-initialized>");

        Looper.prepareMainLooper();

        // 创建ActivityThread实例
        ActivityThread thread = new ActivityThread();
        thread.attach(false);

        if (sMainThreadHandler == null) {
            sMainThreadHandler = thread.getHandler();
        }

        AsyncTask.init();

        if (false) {
            Looper.myLooper().setMessageLogging(new
                    LogPrinter(Log.DEBUG, "ActivityThread"));
        }

        Looper.loop();

        throw new RuntimeException("Main thread loop unexpectedly exited");
    }
}


4.2 家族图谱



4.3 ActivityThread内部类



4.4 ActivityThread工作流程








相关文章推荐

ActivityThread

ActivityThread运行框架 在分析中,我们可以看到真正对应应用进程的不是Application而是ActivityThread。我们从实际的应用堆栈可以看到: NaiveStar...

(1)ActivityThread分析

1. 入口。 以前一直都说Activity的人口是onCreate方法。其实android上一个应用的入口,应该是ActivityThread。和普通的java类一样,入口是一个main方法。 p...
  • ljsbuct
  • ljsbuct
  • 2011年12月22日 11:04
  • 21277

Activity启动过程简析--Binder、Zygote、ActivityThread

一、总体介绍 在Android系统中,Activity和Service是应用程序的核心组件,它们以松藕合的方式组合在一起构成了一个完整的应用程序,这得益于应用程序框架层提供了一套完整的机制来协助应用程...

ActivityThread的main方法究竟做了什么?

ActivityThread的main方法究竟做了什么? 本文原创,转载请经过本人准许。 写在前面:在暴雨天能去上课的都是好学生,能去上班的都是游泳运动员~问大家一个问题:Android中一个应用...
  • MeloDev
  • MeloDev
  • 2016年07月20日 13:41
  • 2960

ActivityThread解析

Android中一个应用程序的真正入口是main方法么?这个问题的答案不是简单的是或者否。         我们知道Android系统基于Linux系统之上,而Linux系统的应用程序是包含了main...
  • tfygg
  • tfygg
  • 2017年02月04日 17:58
  • 592

Android M 5.0,关于ActivityThread和ApplicationThread的解析.

文章仅仅用于个人的学习记录,基本上内容都是网上各中资料,此处摘录过来以自己的理解学习方式记录一下。        ActivityThread和ApplicationThread的理解在你阅读源...

【Android】快速切换到主线程更新UI的几种方法

最近看了网上,在子线程更新UI的方法,说法很多,但都不是很全面。在次我争取做到总结的全面一些,希望以后对自己,对大家都有一些帮助。方法一: view.post(Runnable action)假如该方...

Android 如何判断当前线程是否是主线程

转载请注明本文出自 clevergump 的博客:http://blog.csdn.net/clevergump/article/details/50995612, 谢谢!Android开发中, 有时...

Android主线程到底是什么(一)

Android主线程到底是什么(一)很多做Android应用层开发的同学都知道UI主线程这个说法,且很多初学者在它身上吃了不少亏,常见的错误如“在主线程中做耗时的操作,比如下载大文件”。尽管我们已经非...

Android开发 四大组件是否运行在主线程中?

Android的四大组件是不是运行在主线程中?打了log,做个笔记. 先上图: 图没有说服力,因为log是我写的.哈哈. 1.activity 在onCreate()里面打印当前的线程...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Android ActivityThread(主线程或UI线程)简介
举报原因:
原因补充:

(最多只允许输入30个字)