为什么Activity生命周期函数是运行在UI线程

这是我自己给自己提的问题,或者说是Activity的生命周期函数是怎样运行在主线程的?下面简单分析一下,讨论的问题其实远远不止于这个问题。会涉及到进程的启动,Binder的线程池,ActivityThread中的消息处理。

进程开启

我们最开始接触Android的时候,都知道主线程和非主线程区别,我们可以用Handler来将代码运行在主线程中。而主线程是如何开启的呢?在ActivityThread当中有个公有静态main方法,每次ActivityManagerService请求Zygote进程fork一个新的进程的时候,ActivityManagerService会同时发送一个指定新进程启动哪一个类的参数,ActivityManagerService指定的就是android.app.ActivityThread类。看看ActivityManagerService启动新进程的代码:


if (entryPoint == null) entryPoint = "android.app.ActivityThread";
Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "Start proc: " +
       app.processName);
checkTime(startTime, "startProcess: asking zygote to start proc");
Process.ProcessStartResult startResult = Process.start(entryPoint,
       app.processName, uid, uid, gids, debugFlags, mountExternal,
       app.info.targetSdkVersion, app.info.seinfo, requiredAbi, instructionSet,
       app.info.dataDir, entryPointArgs);

里面的entryPoint就是指定了zygote会启动的类。Process.start的第一个参数。可以看看Process.start函数,它会直接调用Process的startViaZygote私有静态方法,两个方法的参数是一致的:


private static ProcessStartResult startViaZygote(final String processClass,
                             final String niceName,
                             final int uid, final int gid,
                             final int[] gids,
                             int debugFlags, int mountExternal,
                             int targetSdkVersion,
                             String seInfo,
                             String abi,
                             String instructionSet,
                             String appDataDir,
                             String[] extraArgs)
                             throws ZygoteStartFailedEx {
   synchronized(Process.class) {
       ArrayList<String> argsForZygote = new ArrayList<String>();

       // --runtime-args, --setuid=, --setgid=,
       // and --setgroups= must go first
       argsForZygote.add("--runtime-args");
       argsForZygote.add("--setuid=" + uid);
       argsForZygote.add("--setgid=" + gid);
       if ((debugFlags & Zygote.DEBUG_ENABLE_JNI_LOGGING) != 0) {
           argsForZygote.add("--enable-jni-logging");
       }
       if ((debugFlags & Zygote.DEBUG_ENABLE_SAFEMODE) != 0) {
           argsForZygote.add("--enable-safemode");
       }
       if ((debugFlags & Zygote.DEBUG_ENABLE_DEBUGGER) != 0) {
           argsForZygote.add("--enable-debugger");
       }
       if ((debugFlags & Zygote.DEBUG_ENABLE_CHECKJNI) != 0) {
           argsForZygote.add("--enable-checkjni");
       }
       if ((debugFlags & Zygote.DEBUG_ENABLE_JIT) != 0) {
           argsForZygote.add("--enable-jit");
       }
       if ((debugFlags & Zygote.DEBUG_GENERATE_DEBUG_INFO) != 0) {
           argsForZygote.add("--generate-debug-info");
       }
       if ((debugFlags & Zygote.DEBUG_ENABLE_ASSERT) != 0) {
           argsForZygote.add("--enable-assert");
       }
       if (mountExternal == Zygote.MOUNT_EXTERNAL_DEFAULT) {
           argsForZygote.add("--mount-external-default");
       } else if (mountExternal == Zygote.MOUNT_EXTERNAL_READ) {
           argsForZygote.add("--mount-external-read");
       } else if (mountExternal == Zygote.MOUNT_EXTERNAL_WRITE) {
           argsForZygote.add("--mount-external-write");
       }
       argsForZygote.add("--target-sdk-version=" + targetSdkVersion);

       //TODO optionally enable debuger
       //argsForZygote.add("--enable-debugger");

       // --setgroups is a comma-separated list
       if (gids != null && gids.length > 0) {
           StringBuilder sb = new StringBuilder();
           sb.append("--setgroups=");
           int sz = gids.length;
           for (int i = 0; i < sz; i++) {
               if (i != 0) {
                   sb.append(‘,‘);
               }
               sb.append(gids[i]);
           }
           argsForZygote.add(sb.toString());
       }
       if (niceName != null) {
           argsForZygote.add("--nice-name=" + niceName);
       }
       if (seInfo != null) {
           argsForZygote.add("--seinfo=" + seInfo);
       }
       if (instructionSet != null) {
           argsForZygote.add("--instruction-set=" + instructionSet);
       }
       if (appDataDir != null) {
           argsForZygote.add("--app-data-dir=" + appDataDir);
       }
       argsForZygote.add(processClass);
       if (extraArgs != null) {
           for (String arg : extraArgs) {
               argsForZygote.add(arg);
           }
       }
       return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);
   }
}

为了节省空间,我把一些空格给去掉了。这个方法就是将参数组装到argsForZygote当中,存到数组里面。而zygoteSendArgsAndGetResult方法则是通过socket将这些内容发送给Zygote进程:


/**
* Sends an argument list to the zygote process, which starts a new child
* and returns the child‘s pid. Please note: the present implementation
* replaces newlines in the argument list with spaces.
*
* @throws ZygoteStartFailedEx if process start failed for any reason
*/
private static ProcessStartResult zygoteSendArgsAndGetResult(
       ZygoteState zygoteState, ArrayList<String> args)
       throws ZygoteStartFailedEx {
   try {
       /**
        * See com.android.internal.os.ZygoteInit.readArgumentList()
        * Presently the wire format to the zygote process is:
        * a) a count of arguments (argc, in essence)
        * b) a number of newline-separated argument strings equal to count
        *
        * After the zygote process reads these it will write the pid of
        * the child or -1 on failure, followed by boolean to
        * indicate whether a wrapper process was used.
        */
       final BufferedWriter writer = zygoteState.writer;
       final DataInputStream inputStream = zygoteState.inputStream;

       writer.write(Integer.toString(args.size()));
       writer.newLine();

       int sz = args.size();
       for (int i = 0; i < sz; i++) {
           String arg = args.get(i);
           if (arg.indexOf(‘\n‘) >= 0) {
               throw new ZygoteStartFailedEx(
                       "embedded newlines not allowed");
           }
           writer.write(arg);
           writer.newLine();
       }

       writer.flush();

       // Should there be a timeout on this?
       ProcessStartResult result = new ProcessStartResult();
       result.pid = inputStream.readInt();
       if (result.pid < 0) {
           throw new ZygoteStartFailedEx("fork() failed");
       }
       result.usingWrapper = inputStream.readBoolean();
       return result;
   } catch (IOException ex) {
       zygoteState.close();
       throw new ZygoteStartFailedEx(ex);
   }
}

上面就是跟zygote进行socket通信的部分,相信用过socket的看着都非常熟悉。关于zygote启动,并且ActivityManagerService如何建立通信的,想了解的更详细的可以看看老罗这两篇文章Android系统进程Zygote启动过程的源代码分析,[Android应用程序进程启动过程的源代码分析](http://blog.csdn.net/luoshengyang/article/details/6747696)。当然直接看源码是最合适的。

而zygote如何回应的?看看zygote部分启动一个新进程后的代码,zygote中fork之后,子进程会调用RuntimeInit.zygoteInit方法,所以直接从RuntimeInit.zygoteInit开始看。


public static final void zygoteInit(int targetSdkVersion, String[] argv, ClassLoader classLoader)
       throws ZygoteInit.MethodAndArgsCaller {
   if (DEBUG) Slog.d(TAG, "RuntimeInit: Starting application from zygote");

   Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "RuntimeInit");
   redirectLogStreams();

   commonInit();
   nativeZygoteInit();
   applicationInit(targetSdkVersion, argv, classLoader);
}

nativeZygoteInit方法会调用ProcessState开启Binder线程池,供与Binder驱动通信使用。而applicationInit会调用invokeStaticMain方法调用ActivityManagerService传入的ActivityThread类的main方法。

其实整个流程就跟我们使用java命令运行程序是一样的。

main方法里面会设置主线程loop,然后调用Looper.loop()处理消息:


public static void main(String[] args) {
   Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "ActivityThreadMain");
   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());

   AndroidKeyStoreProvider.install();

   // Make sure TrustedCertificateStore looks in the right place for CA certificates
   final File configDir = Environment.getUserConfigDirectory(UserHandle.myUserId());
   TrustedCertificateStore.setDefaultUserDirectory(configDir);

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

   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();  //消息loop

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

Handler机制的使用

而ActivityManagerService使用binder机制(IApplicationThread)调用某个进程的四大组件时,ActivityThread部分,一开始是运行在Binder线程池的,然后通过Handler机制发送消息给主线程,运行相关内容,比如说启动Activity,IApplicationThread的方法scheduleLaunchActivity实现就如此:


private class ApplicationThread extends ApplicationThreadNative {

@Override
public final void scheduleLaunchActivity(Intent intent, IBinder token, int ident,
       ActivityInfo info, Configuration curConfig, Configuration overrideConfig,
       CompatibilityInfo compatInfo, String referrer, IVoiceInteractor voiceInteractor,
       int procState, Bundle state, PersistableBundle persistentState,
       List<ResultInfo> pendingResults, List<ReferrerIntent> pendingNewIntents,
       boolean notResumed, boolean isForward, ProfilerInfo profilerInfo) {

   updateProcessState(procState, false);

   ActivityClientRecord r = new ActivityClientRecord();

   r.token = token;
   r.ident = ident;
   r.intent = intent;
   r.referrer = referrer;
   r.voiceInteractor = voiceInteractor;
   r.activityInfo = info;
   r.compatInfo = compatInfo;
   r.state = state;
   r.persistentState = persistentState;

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

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

   r.profilerInfo = profilerInfo;

   r.overrideConfig = overrideConfig;
   updatePendingConfiguration(curConfig);

   sendMessage(H.LAUNCH_ACTIVITY, r);
}

}

最终消息处理的地方是在类ActivityThread.H(Handler的子类)的handleMessage方法中,ActivityThread.H的looper就是主线程的looper,这里就已经是运行在主线程了:


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;

}

其他的四大组件也是一样的

时间: 2024-10-21 07:40:40

为什么Activity生命周期函数是运行在UI线程的相关文章

Activity生命周期函数、onSaveInstanceState()和onRestoreInstanceState()的介绍

本文涉及了Activity中的 onSaveInstanceState() 和 onRestoreInstanceState()方法,需要注意的他们并不是生命周期方法.我放在这是为了整合起来讲解. 一.生命周期中的方法调用时机 本文转自:http://blog.csdn.net/android_tutor/article/details/5772285 1) 首次执行时执行:onCreate()->onStart()->onResume() 2) 部分可见(被对话框等遮挡)时执行:onPaus

servlet的生命周期与运行时的线程模型

第 14 章 生命周期 注意 讲一下servlet的生命周期与运行时的线程模型,对了解servlet的运行原理有所帮助,这样才能避免一些有冲突的设计. 如果你不满足以下任一条件,请继续阅读,否则请跳过此后的部分,进入下一章:第 15 章 分页. 了解servlet的生命周期. 了解servlet运行时的线程模型,及设计程序时需要注意的部分. 14.1. 生命周期 我们之前使用的都是javax.servlet.http.HttpServlet,这个类实现了javax.servlet.Servlet

Unity3D安卓交互 - 使代码运行在UI线程

runOnUiThread(new Runnable() { public void run() { // TODO Auto-generated method stub } });

如何使程序运行在UI线程

context.runOnUiThread(new Runnable() { @Override public void run() { _prop = new Prop(buyType, moneyPay, product); context.doPay(); } });

java攻城狮之路(Android篇)--Activity生命

1 写一个类 extends Activity Activity是android的四大组件之一. Activity的激活分为显式意图激活和隐式意图激活. 如果一个activity希望别人隐式意图激活:则要配置过滤器1 action = ""2 有一个缺省的category,(可以有多个category),若不配置该类型会发生这样的一个错误:Caused by: android.content.ActivityNotFoundException: No Activity found to

Activity生命周期.lanchMode.保存状态

Activity生命周期 每一个Android应用程序在运行时,对于底层的Linux Kernel而言都是一个单独的进程,但是对于Android系统而言,因为局限于手机画面的大小与使用的考虑,不能把每一个运行中的应用程序窗口都显示出来. 所以通常手机系统的界面一次仅显示一个应用程序窗口,Android使用了Activity的概念来表示界面. 运行中的应用程序分为五大类,分别是: 前景模式:foreground process 可见模式:visible process 背景模式:backgroun

Activity生命周期讲解

前言: 一直想着写一些Android基础知识分享给大家,但是有时候又觉得怕写不好误导了大家学习Android,思前想后觉得还是去Android官网看看,发现在Android官网上其实就能学习到很多知识,并且最新的知识他都会及时的更新,所以决定按照官网带领大家学习Android知识,在中间会穿插本人在做项目时的一些体会和总结. 应用程序的入口: 所有学习Android的基本上都从学习Activity开始,因为它是Android的大门,相当于Java程序的入口函数main().当你查看一个Java项

Android专题2——Activity生命周期

Activity生命周期函数 重写上述每个函数,加提示信息 启动MainActivity后 点击SecondActivity后 首先 其次 接着 重新返回MainActivity以后

Android UI线程和非UI线程

UI线程及Android的单线程模型原则 当应用启动,系统会创建一个主线程(main thread). 这个主线程负责向UI组件分发事件(包括绘制事件),也是在这个主线程里,你的应用和Android的UI组件(components from the Android UI toolkit (components from the android.widget and android.view packages))发生交互. 所以main thread也叫UI thread也即UI线程. 系统不会为