码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2016-08-19 01:05:14      阅读:261      评论:0      收藏:0      [点我收藏+]

标签:

这是我自己给自己提的问题,或者说是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;

}

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

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

标签:

原文地址:http://blog.csdn.net/xxxzhi/article/details/52246152

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!