版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/sjdjdjdjahd/article/details/103254787

Activity是Android应用与用户交互的界面,了解Activity的启动流程可以加深我们对Activity理解。sdk版本25

一、发起启动Activity的请求

通常我们会通过startActivity()来打开一个新的Activity。

  startActivity(new Intent(this, SecondActivity.class));
1、Activity & startActivityForResult()

该方法最终会调用Activity的 startActivityForResult方法:

    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode,@Nullable Bundle options) {if (mParent == null) {options = transferSpringboardActivityOptions(options);Instrumentation.ActivityResult ar =mInstrumentation.execStartActivity(this, mMainThread.getApplicationThread(), mToken, this,intent, requestCode, options);if (ar != null) {mMainThread.sendActivityResult(mToken, mEmbeddedID, requestCode, ar.getResultCode(),ar.getResultData());}if (requestCode >= 0) {mStartedActivity = true;}cancelInputsAndStartExitTransition(options);} else {if (options != null) {mParent.startActivityFromChild(this, intent, requestCode, options);} else {// Note we want to go through this method for compatibility with// existing applications that may have overridden it.mParent.startActivityFromChild(this, intent, requestCode);}}}

当Activity还没被创建mParent 为null,执行Instrumentation类的execStartActivity()方法,该参数中mMainThread.getApplicationThread()返回的是一个ApplicationThread对象,而ApplicationThread又是IBinder的一个子类,负责后面ActivityThread和AMS之间的通信。

2、Instrumentation & execStartActivity方法
    public ActivityResult execStartActivity(Context who, IBinder contextThread, IBinder token, Activity target,Intent intent, int requestCode, Bundle options) {IApplicationThread whoThread = (IApplicationThread) contextThread;...try {intent.migrateExtraStreamToClipData();intent.prepareToLeaveProcess(who);int result = ActivityManagerNative.getDefault().startActivity(whoThread, who.getBasePackageName(), intent,intent.resolveTypeIfNeeded(who.getContentResolver()),token, target != null ? target.mEmbeddedID : null,requestCode, 0, null, options);checkStartActivityResult(result, intent);} catch (RemoteException e) {throw new RuntimeException("Failure from system", e);}return null;}

在execStartActivity方法中会执行ActivityManagerNative.getDefault().startActivity方法。来看一下ActivityManagerNative.getDefault()方法返回值。

3、ActivityManagerNative & getDefault()
    static public IActivityManager getDefault() {return gDefault.get();}private static final Singleton<IActivityManager> gDefault = new Singleton<IActivityManager>() {protected IActivityManager create() {IBinder b = ServiceManager.getService("activity");if (false) {Log.v("ActivityManager", "default service binder = " + b);}IActivityManager am = asInterface(b);if (false) {Log.v("ActivityManager", "default service = " + am);}return am;}};

gDefault 是一个单例方法,该方法返回一个IActivityManager 对象。而ServiceManager.getService("activity");则获得一个ActivityManagerService 服务。并将这个ActivityManagerService 通过asInterface(b)方法返回。

asInterface(b)方法如下:

    static public IActivityManager asInterface(IBinder obj) {if (obj == null) {return null;}IActivityManager in =(IActivityManager)obj.queryLocalInterface(descriptor);if (in != null) {return in;}return new ActivityManagerProxy(obj);}

可以看到asInterface返回的是一个ActivityManagerProxy代理类。即ActivityManagerNative.getDefault()返回的是ActivityManagerProxy对象,所以我们看一下ActivityManagerProxy的startActivity方法

4、ActivityManagerProxy & startActivity
class ActivityManagerProxy implements IActivityManager
{public ActivityManagerProxy(IBinder remote){mRemote = remote;}public IBinder asBinder(){return mRemote;}public int startActivity(IApplicationThread caller, String callingPackage, Intent intent,String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException {Parcel data = Parcel.obtain();Parcel reply = Parcel.obtain();data.writeInterfaceToken(IActivityManager.descriptor);data.writeStrongBinder(caller != null ? caller.asBinder() : null);data.writeString(callingPackage);intent.writeToParcel(data, 0);data.writeString(resolvedType);data.writeStrongBinder(resultTo);data.writeString(resultWho);data.writeInt(requestCode);data.writeInt(startFlags);if (profilerInfo != null) {data.writeInt(1);profilerInfo.writeToParcel(data, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);} else {data.writeInt(0);}if (options != null) {data.writeInt(1);options.writeToParcel(data, 0);} else {data.writeInt(0);}mRemote.transact(START_ACTIVITY_TRANSACTION, data, reply, 0);reply.readException();int result = reply.readInt();reply.recycle();data.recycle();return result;}...
}

先看一下ActivityManagerProxy 的继承关系

-> IInterface 
- -> IActivityManager
- - -> ActivityManagerProxy 

所以ActivityManagerProxy 是一个典型的Binder机制,目的为了将消息从ActivityManagerNative发送到SystemService进程中,此处SystemService是ActivityManagerService。

在ActivityManagerProxy 中,通过Binder机制将消息发送到ActivityManagerService中,下面看一下ActivityManagerService的startActivity方法

二、ActivityManagerService 接收启动请求

1、下面来看ActivityManagerService 的startActivity()方法

    @Overridepublic final int startActivity(IApplicationThread caller, String callingPackage,Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode,int startFlags, ProfilerInfo profilerInfo, Bundle bOptions) {return startActivityAsUser(caller, callingPackage, intent, resolvedType, resultTo,resultWho, requestCode, startFlags, profilerInfo, bOptions,UserHandle.getCallingUserId());}

在startActivity()会调用startActivityAsUser()方法,而在startActivityAsUser方法中又会调用ActivityStarterstartActivityMayWait()方法

2、ActivityStarter & startActivityMayWait()
    final int startActivityMayWait(IApplicationThread caller, int callingUid,String callingPackage, Intent intent, String resolvedType,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,IBinder resultTo, String resultWho, int requestCode, int startFlags,ProfilerInfo profilerInfo, IActivityManager.WaitResult outResult, Configuration config,Bundle bOptions, boolean ignoreTargetSecurity, int userId,IActivityContainer iContainer, TaskRecord inTask) {...int res = startActivityLocked(caller, intent, ephemeralIntent, resolvedType,aInfo, rInfo, voiceSession, voiceInteractor,resultTo, resultWho, requestCode, callingPid,callingUid, callingPackage, realCallingPid, realCallingUid, startFlags,options, ignoreTargetSecurity, componentSpecified, outRecord, container,inTask);...return res;
}

上面方法又会继续调用startActivityLocked方法。

3、ActivityStarter & startActivityLocked()
    final int startActivityLocked(IApplicationThread caller, Intent intent, Intent ephemeralIntent,String resolvedType, ActivityInfo aInfo, ResolveInfo rInfo,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,IBinder resultTo, String resultWho, int requestCode, int callingPid, int callingUid,String callingPackage, int realCallingPid, int realCallingUid, int startFlags,ActivityOptions options, boolean ignoreTargetSecurity, boolean componentSpecified,ActivityRecord[] outActivity, ActivityStackSupervisor.ActivityContainer container,TaskRecord inTask) {int err = ActivityManager.START_SUCCESS;...ActivityRecord r = new ActivityRecord(mService, callerApp, callingUid, callingPackage,intent, resolvedType, aInfo, mService.mConfiguration, resultRecord, resultWho,requestCode, componentSpecified, voiceSession != null, mSupervisor, container,options, sourceRecord);...try {mService.mWindowManager.deferSurfaceLayout();err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,true, options, inTask);} finally {mService.mWindowManager.continueSurfaceLayout();}return err;}

在此方法中创建了ActivityRecord 对象,并调用了startActivityUnchecked方法。

3、ActivityStarter & startActivityUnchecked()
    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {...mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,mOptions);...return START_SUCCESS;
}

这个方法里面会判断Activity的启动模式,并判断是否需要回调onNewIntent()方法。
最终会执行mSupervisor.resumeFocusedStackTopActivityLocked()方法。

而resumeFocusedStackTopActivityLocked中会执行ActivityStack的resumeTopActivityUncheckedLocked方法。在resumeTopActivityUncheckedLocked中,会执行resumeTopActivityInnerLocked方法。用来将Activity显示在栈顶

4、ActivityStack & resumeTopActivityInnerLocked

resumeTopActivityInnerLocked方法做的事情太多了。这里分开来讲。

①、执行栈顶Activity的onPause方法。
        // We need to start pausing the current activity so the top one can be resumed...final boolean dontWaitForPause = (next.info.flags & FLAG_RESUME_WHILE_PAUSING) != 0;boolean pausing = mStackSupervisor.pauseBackStacks(userLeaving, next, dontWaitForPause);if (mResumedActivity != null) {if (DEBUG_STATES) Slog.d(TAG_STATES,"resumeTopActivityLocked: Pausing " + mResumedActivity);pausing |= startPausingLocked(userLeaving, false, next, dontWaitForPause);}

ActivityStack & startPausingLocked()

 	ActivityRecord mResumedActivity = null;final boolean startPausingLocked(boolean userLeaving, boolean uiSleeping,ActivityRecord resuming, boolean dontWait) {ActivityRecord prev = mResumedActivity;...if (prev.app != null && prev.app.thread != null) {try {...prev.app.thread.schedulePauseActivity(prev.appToken, prev.finishing,userLeaving, prev.configChangeFlags, dontWait);} catch (Exception e) {...}} else {...}}

这里会调用prev.app.thread的schedulePauseActivity方法。thread其实就是ActivityThread的内部类ApplicationThread。

ApplicationThread & schedulePauseActivity

        public final void schedulePauseActivity(IBinder token, boolean finished,boolean userLeaving, int configChanges, boolean dontReport) {int seq = getLifecycleSeq();if (DEBUG_ORDER) Slog.d(TAG, "pauseActivity " + ActivityThread.this+ " operation received seq: " + seq);sendMessage(finished ? H.PAUSE_ACTIVITY_FINISHING : H.PAUSE_ACTIVITY,token,(userLeaving ? USER_LEAVING : 0) | (dontReport ? DONT_REPORT : 0),configChanges,seq);}

上面方面通过handler机制在接收消息的地方会执行handlePauseActivity()方法。

    private void handlePauseActivity(IBinder token, boolean finished,boolean userLeaving, int configChanges, boolean dontReport, int seq) {ActivityClientRecord r = mActivities.get(token);if (DEBUG_ORDER) Slog.d(TAG, "handlePauseActivity " + r + ", seq: " + seq);if (!checkAndUpdateLifecycleSeq(seq, r, "pauseActivity")) {return;}if (r != null) {//Slog.v(TAG, "userLeaving=" + userLeaving + " handling pause of " + r);if (userLeaving) {performUserLeavingActivity(r);}r.activity.mConfigChangeFlags |= configChanges;performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");// Make sure any pending writes are now committed.if (r.isPreHoneycomb()) {QueuedWork.waitToFinish();}// Tell the activity manager we have paused.if (!dontReport) {try {ActivityManagerNative.getDefault().activityPaused(token);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}}mSomeActivitiesChanged = true;}}

在handlePauseActivity方法中后面会执行一系列方法:

handlePauseActivity -> performPauseActivity -> performPauseActivityIfNeeded 
-> Instrumentation.callActivityOnPause -> activity.performPause() ->  activity.onPause()

经过一些列的方法调用,最终会执行activity的onPause()方法。

上面还有一句ActivityManagerNative.getDefault().activityPaused(token);。这段代码会执行ActivityManagerService中的activityPaused。最终又会执行到我们的resumeTopActivityInnerLocked中,该方法最后会执行mStackSupervisor.startSpecificActivityLocked方法

②、ActivityStackSupervisor & startSpecificActivityLocked
    void startSpecificActivityLocked(ActivityRecord r,boolean andResume, boolean checkConfig) {// Is this activity's application already running?ProcessRecord app = mService.getProcessRecordLocked(r.processName,r.info.applicationInfo.uid, true);r.task.stack.setLaunchTime(r);if (app != null && app.thread != null) {try {if ((r.info.flags&ActivityInfo.FLAG_MULTIPROCESS) == 0|| !"android".equals(r.info.packageName)) {// Don't add this if it is a platform component that is marked// to run in multiple processes, because this is actually// part of the framework so doesn't make sense to track as a// separate apk in the process.app.addPackage(r.info.packageName, r.info.applicationInfo.versionCode,mService.mProcessStats);}realStartActivityLocked(r, app, andResume, checkConfig);return;} catch (RemoteException e) {Slog.w(TAG, "Exception when starting activity "+ r.intent.getComponent().flattenToShortString(), e);}// If a dead object exception was thrown -- fall through to// restart the application.}mService.startProcessLocked(r.processName, r.info.applicationInfo, true, 0,"activity", r.intent.getComponent(), false, false, true);}

在此方法中先判断Activity所在进程是否已经启动,若是启动的话则执行realStartActivityLocked方法,真正启动Activity的地方。若是没有启动则先执行mService.startProcessLocked启动Activity进程,在启动Activity

三、启动Activity所在进程

1、ActivityManagerService & startProcessLocked
    private final void startProcessLocked(ProcessRecord app, String hostingType,String hostingNameStr, String abiOverride, String entryPoint, String[] entryPointArgs) {...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);...}

在startProcessLocked中会调用Process.start()方法启动进程,并且传入了processClass需要启动进程的类名"android.app.ActivityThread"

2、启动进程 Process.start
    /*** Start a new process.* * <p>If processes are enabled, a new process is created and the* static main() function of a <var>processClass</var> is executed there.* The process will continue running after this function returns.* @param processClass The class to use as the process's main entry*                     point.* @param niceName A more readable name to use for the process.* @param uid The user-id under which the process will run.* @param gid The group-id under which the process will run.* @param gids Additional group-ids associated with the process.* @param debugFlags Additional flags.* @param targetSdkVersion The target SDK version for the app.* @param seInfo null-ok SELinux information for the new process.* @param abi non-null the ABI this app should be started with.* @param instructionSet null-ok the instruction set to use.* @param appDataDir null-ok the data directory of the app.* @param zygoteArgs Additional arguments to supply to the zygote process.* * @return An object that describes the result of the attempt to start the process.* @throws RuntimeException on fatal start failure* * {@hide}*/public static final ProcessStartResult start(final String processClass,final String niceName,int uid, int gid, int[] gids,int debugFlags, int mountExternal,int targetSdkVersion,String seInfo,String abi,String instructionSet,String appDataDir,String[] zygoteArgs) {try {return startViaZygote(processClass, niceName, uid, gid, gids,debugFlags, mountExternal, targetSdkVersion, seInfo,abi, instructionSet, appDataDir, zygoteArgs);} catch (ZygoteStartFailedEx ex) {Log.e(LOG_TAG,"Starting VM process through Zygote failed");throw new RuntimeException("Starting VM process through Zygote failed", ex);}}

从该方法的注释也可以看到该方法的作用就是启动一个新的进程。并且参数processClass作为进程的入口类,并启动该类中的main()方法。而该类就是android.app.ActivityThread。然后执行startViaZygote方法,通过
zygote 加载进程。

3、Process & startViaZygote
    /*** Starts a new process via the zygote mechanism.*/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) {...return zygoteSendArgsAndGetResult(openZygoteSocketIfNeeded(abi), argsForZygote);}}

该方法的注释是:通过zygote机制来加载执行新的进程。
继续查看zygoteSendArgsAndGetResult()方法

3、Process & zygoteSendArgsAndGetResult
    /*** 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 {// Throw early if any of the arguments are malformed. This means we can// avoid writing a partial response to the zygote.int sz = args.size();for (int i = 0; i < sz; i++) {if (args.get(i).indexOf('\n') >= 0) {throw new ZygoteStartFailedEx("embedded newlines not allowed");}}/*** 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();for (int i = 0; i < sz; i++) {String arg = args.get(i);writer.write(arg);writer.newLine();}writer.flush();// Should there be a timeout on this?ProcessStartResult result = new ProcessStartResult();// Always read the entire result from the input stream to avoid leaving// bytes in the stream for future process starts to accidentally stumble// upon.result.pid = inputStream.readInt();result.usingWrapper = inputStream.readBoolean();if (result.pid < 0) {throw new ZygoteStartFailedEx("fork() failed");}return result;} catch (IOException ex) {zygoteState.close();throw new ZygoteStartFailedEx(ex);}}

在该方法中会通过socket通信的方式让Zygote进程fork出了一个新的进程。并且根据反射加载我们之前传入类名android.app.ActivityThread,并执行ActivityThread的main()方法。

四、执行ActivityThread的main()方法

    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 libcoreEventLogger.setReporter(new EventLoggingReporter());// Make sure TrustedCertificateStore looks in the right place for CA certificatesfinal 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(newLogPrinter(Log.DEBUG, "ActivityThread"));}// End of event ActivityThreadMain.Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);Looper.loop();throw new RuntimeException("Main thread loop unexpectedly exited");}

在main()方法中对Looper进行绑定,创建了一个UI线程的消息队列,创建了ActivityThread对象,并且执行了ActivityThread的attach()方法。下面来看一下attach()方法做了些什么

    private void attach(boolean system) {sCurrentActivityThread = this;mSystemThread = system;if (!system) {...final IActivityManager mgr = ActivityManagerNative.getDefault();try {mgr.attachApplication(mAppThread);} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}// Watch for getting close to heap limit.//添加一个垃圾回收观察者,每当系统触发垃圾回收的时候就会在run方法里面去//计算应用使用了多少内存,如果超过总量的四分之三就会尝试释放内存BinderInternal.addGcWatcher(new Runnable() {@Override public void run() {if (!mSomeActivitiesChanged) {return;}Runtime runtime = Runtime.getRuntime();long dalvikMax = runtime.maxMemory();long dalvikUsed = runtime.totalMemory() - runtime.freeMemory();if (dalvikUsed > ((3*dalvikMax)/4)) {if (DEBUG_MEMORY_TRIM) Slog.d(TAG, "Dalvik max=" + (dalvikMax/1024)+ " total=" + (runtime.totalMemory()/1024)+ " used=" + (dalvikUsed/1024));mSomeActivitiesChanged = false;try {mgr.releaseSomeActivities(mAppThread);} catch (RemoteException e) {throw e.rethrowFromSystemServer();}}}});...} }

我们知道Binder机制是C/S模式,ActivityManagerNative和ActivityManagerService就是一个Binder机制,ActivityManagerNative相当于客户端,所以上面mgr.attachApplication(mAppThread);最终会执行ActivityManagerService的attachApplication方法

1、ActivityManagerService & attachApplication()
    @Overridepublic final void attachApplication(IApplicationThread thread) {synchronized (this) {int callingPid = Binder.getCallingPid();final long origId = Binder.clearCallingIdentity();attachApplicationLocked(thread, callingPid);Binder.restoreCallingIdentity(origId);}}

该方法会继续执行attachApplicationLocked方法

2、ActivityManagerService & attachApplicationLocked()
		...// See if the top visible activity is waiting to run in this process...if (normalMode) {try {if (mStackSupervisor.attachApplicationLocked(app)) {didSomething = true;}} catch (Exception e) {Slog.wtf(TAG, "Exception thrown launching activities in " + app, e);badApp = true;}}...

继续执行ActivityStackSupervisor.attachApplicationLocked方法

3、ActivityStackSupervisor & attachApplicationLocked
		...if (realStartActivityLocked(hr, app, true, true)) {didSomething = true;}...

这里会执行realStartActivityLocked方法,真正启动Activity的方法。

五、启动Activity

经过一系列准备,终于到了真正启动Activity的时候了

1、ActivityStackSupervisor & realStartActivityLocked()
    final boolean realStartActivityLocked(ActivityRecord r, ProcessRecord app,boolean andResume, boolean checkConfig) throws RemoteException {...app.thread.scheduleLaunchActivity(new Intent(r.intent), r.appToken,System.identityHashCode(r), r.info, new Configuration(mService.mConfiguration),new Configuration(task.mOverrideConfig), r.compat, r.launchedFromPackage,task.voiceInteractor, app.repProcState, r.icicle, r.persistentState, results,newIntents, !andResume, mService.isNextTransitionForward(), profilerInfo);...}

这里面通过调用 app.thread的scheduleLaunchActivity来启动Activity。这里的thread是ActivityThread的内部类ApplicationThread。ApplicationThread也是一个Binder类。所以真正执行scheduleLaunchActivity方法的地方在ActivityThread的内部类ApplicationThread中。

2、ActivityThread & scheduleLaunchActivity()
        @Overridepublic 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);}

这里面是一个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");final ActivityClientRecord r = (ActivityClientRecord) msg.obj;r.packageInfo = getPackageInfoNoCheck(r.activityInfo.applicationInfo, r.compatInfo);handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);} break;}

执行handleLaunchActivity方法

3、ActivityThread & handleLaunchActivity()
		...Activity a = performLaunchActivity(r, customIntent);if (a != null) {r.createdConfig = new Configuration(mConfiguration);reportSizeConfigurations(r);Bundle oldState = r.state;handleResumeActivity(r.token, false, r.isForward,!r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);...

然后执行performLaunchActivity方法启动Activity

4、ActivityThread & performLaunchActivity()

    private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {...Activity activity = null;try {java.lang.ClassLoader cl = r.packageInfo.getClassLoader();activity = mInstrumentation.newActivity(cl, component.getClassName(), r.intent);StrictMode.incrementExpectedActivityCount(activity.getClass());r.intent.setExtrasClassLoader(cl);r.intent.prepareToEnterProcess();if (r.state != null) {r.state.setClassLoader(cl);}} catch (Exception e) {if (!mInstrumentation.onException(activity, e)) {throw new RuntimeException("Unable to instantiate activity " + component+ ": " + e.toString(), e);}}...Application app = r.packageInfo.makeApplication(false, mInstrumentation);return activity;}
  • 1、通过mInstrumentation.newActivity()方法,使用类加载器创建一个Activity

        public Activity newActivity(ClassLoader cl, String className,Intent intent)throws InstantiationException, IllegalAccessException,ClassNotFoundException {return (Activity)cl.loadClass(className).newInstance();
    }
    
  • 2、通过makeApplication方法创建一个Application 对象

        public Application makeApplication(boolean forceDefaultAppClass,Instrumentation instrumentation) {//如果已经创建过了则直接返回if (mApplication != null) {return mApplication;}...Application app = null;String appClass = mApplicationInfo.className;if (forceDefaultAppClass || (appClass == null)) {appClass = "android.app.Application";}try {java.lang.ClassLoader cl = getClassLoader();if (!mPackageName.equals("android")) {Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,"initializeJavaContextClassLoader");initializeJavaContextClassLoader();Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);}ContextImpl appContext = ContextImpl.createAppContext(mActivityThread, this);app = mActivityThread.mInstrumentation.newApplication(cl, appClass, appContext);appContext.setOuterContext(app);} catch (Exception e) {...}mActivityThread.mAllApplications.add(app);mApplication = app;if (instrumentation != null) {try {instrumentation.callApplicationOnCreate(app);} catch (Exception e) {...}}...return app;
    }
    
    在callApplicationOnCreate方法中调用Application中调用onCreate()方法
        public void callApplicationOnCreate(Application app) {app.onCreate();}
    
  • 3、创建Context对象,并且调用Activity的attach()方法

       Context appContext = createBaseContextForActivity(r, activity);CharSequence title = r.activityInfo.loadLabel(appContext.getPackageManager());Configuration config = new Configuration(mCompatConfiguration);if (r.overrideConfig != null) {config.updateFrom(r.overrideConfig);}if (DEBUG_CONFIGURATION) Slog.v(TAG, "Launching activity "+ r.activityInfo.name + " with config " + config);Window window = null;if (r.mPendingRemoveWindow != null && r.mPreserveWindow) {window = r.mPendingRemoveWindow;r.mPendingRemoveWindow = null;r.mPendingRemoveWindowManager = null;}activity.attach(appContext, this, getInstrumentation(), r.token,r.ident, app, r.intent, r.activityInfo, title, r.parent,r.embeddedID, r.lastNonConfigurationInstances, config,r.referrer, r.voiceInteractor, window);	
    
  • 4、调用Activity的onCreate()

      if (r.isPersistable()) {mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);} else {mInstrumentation.callActivityOnCreate(activity, r.state);}
    
    Instrumentation类中callActivityOnCreate()
     public void callActivityOnCreate(Activity activity, Bundle icicle,PersistableBundle persistentState) {prePerformCreate(activity);activity.performCreate(icicle, persistentState);postPerformCreate(activity);}
    
    Activity中performCreate()
    final void performCreate(Bundle icicle) {restoreHasCurrentPermissionRequest(icicle);onCreate(icicle);mActivityTransitionState.readState(icicle);performCreateCommon();
    }
    
  • 5、Activity的onStart()

    if (!r.activity.mFinished) {activity.performStart();r.stopped = false;
    }	
    //Activity类中方法
    final void performStart() {...mInstrumentation.callActivityOnStart(this);
    }
    //Instrumentation类
    public void callActivityOnStart(Activity activity) {activity.onStart();
    }
    
  • 其他方法

    • onRestoreInstanceState
                if (!r.activity.mFinished) {if (r.isPersistable()) {if (r.state != null || r.persistentState != null) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,r.persistentState);}} else if (r.state != null) {mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);}}
    

到这里performLaunchActivity的方法就执行完毕了。我们的新创建Activity已经经历了onCreateonStart方法了。现在我们回到ActivityThread的handleLaunchActivity()中,执行完performLaunchActivity方法后,下面还有个handleResumeActivity();方法。

ActivityThread & handleResumeActivity
    final void handleResumeActivity(IBinder token,boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {...r = performResumeActivity(token, clearHide, reason);...}

继续执行performResumeActivity

ActivityThread & performResumeActivity
    public final ActivityClientRecord performResumeActivity(IBinder token,boolean clearHide, String reason) {ActivityClientRecord r = mActivities.get(token);...r.activity.performResume();...}

同理,查看Activity的performResume

Activity& performResume()
    final void performResume() {mInstrumentation.callActivityOnResume(this);...}
Instrumentation & callActivityOnResume
    public void callActivityOnResume(Activity activity) {activity.mResumed = true;activity.onResume();...}

执行activity.onResume(),到这里新的Activity已经显示在屏幕上,并可以与用户进行交互了。

六、栈顶Activity的onStop()

我们已经知道了栈顶Activity的onStop()方法是在新Activity的onResume()之后调用的。所以回到handleResumeActivity方法中去

1、ActivityThread & handleResumeActivity()
	...Looper.myQueue().addIdleHandler(new Idler());...

在handleResumeActivity方法的尾部有上面的代码,查看Idler的具体实现

    private class Idler implements MessageQueue.IdleHandler {@Overridepublic final boolean queueIdle() {ActivityClientRecord a = mNewActivities;if (a != null) {IActivityManager am = ActivityManagerNative.getDefault();ActivityClientRecord prev;do {   if (a.activity != null && !a.activity.mFinished) {try {am.activityIdle(a.token, a.createdConfig, stopProfiling);a.createdConfig = null;} catch (RemoteException ex) {throw ex.rethrowFromSystemServer();}}} while (a != null);}  }}

因为ActivityManagerNative相等于ActivityManagerService的客户端,所以activityIdle最终会在ActivityManagerService中执行

2、ActivityManagerService & activityIdle()
    @Overridepublic final void activityIdle(IBinder token, Configuration config, boolean stopProfiling) {final long origId = Binder.clearCallingIdentity();synchronized (this) {ActivityStack stack = ActivityRecord.getStackLocked(token);if (stack != null) {ActivityRecord r =mStackSupervisor.activityIdleInternalLocked(token, false, config);if (stopProfiling) {if ((mProfileProc == r.app) && (mProfileFd != null)) {try {mProfileFd.close();} catch (IOException e) {}clearProfilerLocked();}}}}Binder.restoreCallingIdentity(origId);}

此方法会执行StackSupervisor.activityIdleInternalLocked()

3、StackSupervisor & activityIdleInternalLocked()
    final ActivityRecord activityIdleInternalLocked(final IBinder token, boolean fromTimeout,Configuration config) {...for (int i = 0; i < NS; i++) {r = stops.get(i);final ActivityStack stack = r.task.stack;if (stack != null) {if (r.finishing) {stack.finishCurrentActivityLocked(r, ActivityStack.FINISH_IMMEDIATELY, false);} else {stack.stopActivityLocked(r);}}}...return r;}

此方法会执行ActivityStack.stopActivityLocked()

4、ActivityStack & stopActivityLocked
    final void stopActivityLocked(ActivityRecord r) {	...r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);...}

通用调用了ActivityThread内部类ApplicationThread的scheduleStopActivity方法

5、ActivityThread & scheduleStopActivity
        public final void scheduleStopActivity(IBinder token, boolean showWindow,int configChanges) {int seq = getLifecycleSeq();if (DEBUG_ORDER) Slog.d(TAG, "stopActivity " + ActivityThread.this+ " operation received seq: " + seq);sendMessage(showWindow ? H.STOP_ACTIVITY_SHOW : H.STOP_ACTIVITY_HIDE,token, 0, configChanges, seq);}

同样适用handler机制。在接收消息的地方执行handleStopActivity方法

6、ActivityThread & handleStopActivity
    private void handleStopActivity(IBinder token, boolean show, int configChanges, int seq) {ActivityClientRecord r = mActivities.get(token);if (!checkAndUpdateLifecycleSeq(seq, r, "stopActivity")) {return;}r.activity.mConfigChangeFlags |= configChanges;StopInfo info = new StopInfo();performStopActivityInner(r, info, show, true, "handleStopActivity");...}

然后执行performStopActivityInner()

    private void performStopActivityInner(ActivityClientRecord r,StopInfo info, boolean keepShown, boolean saveState, String reason) {if (r != null) {// One must first be paused before stopped...performPauseActivityIfNeeded(r, reason);// Next have the activity save its current state and managed dialogs...if (!r.activity.mFinished && saveState) {if (r.state == null) {callCallActivityOnSaveInstanceState(r);}}if (!keepShown) {// Now we are idle.r.activity.performStop(false /*preserveWindow*/);}}}

这里面有两个逻辑,一个会执行onSaveInstanceState,另一个会执行performStop()来停止Activity。

7、Activity & performStop
    final void performStop(boolean preserveWindow) {...mInstrumentation.callActivityOnStop(this);...}

同样在Instrumentation的callActivityOnStop方法中调用activity的onStop方法

    public void callActivityOnStop(Activity activity) {activity.onStop();}

到这里Activity的启动流程就结束了。

总结

断断续续看了差不多两天,有时候看的头晕眼花了。还好总算把Activity的启动流程给过了一遍。中途迷失了好几次。

  • Activity的启动流程是从startActivity或startActivityForResult开始的。Activity内部最终调用startActivityForResult方法
  • Activity的启动流程涉及到多进程通信,通过Binder机制完成通信的。例如:ActivityThread 和 ActivityManagerService 之间的通信
  • ActivityThread通过Binder线程池接收消息后,会通过Handler机制将其在主线程中回调。
  • ActivityManagerService启动Activity的时候,先判断判断Activity所在进程是否创建,然后才执行启动流程
  • ActivityManagerService会通过Socket与Zygote之间通信,通知Zygote进程fork出新的进程,然后执行ActivityThread的mani方法;

参考:
开发艺术探索
(Android 9.0)Activity启动流程源码分析
Android源码解析之(十四)–>Activity启动流程

查看全文
如若内容造成侵权/违法违规/事实不符,请联系编程学习网邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

相关文章

  1. JSP隐含对象学习笔记

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qq_Lisa/article/details/103277309在web目录里创建用户注册页面register.jsp在web目录里创建处理注册页面do_register.jsp…...

    2024/4/23 6:42:52
  2. 机器学习小目标--简单线性回归&最小二乘法 &多元线性回归

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/beautiful_well/article/details/103275846线性回归(又名普通最小二乘法)线性回归,或者普通最小二乘法,是回归问题最简…...

    2024/4/26 15:28:30
  3. Go开发 之 流程控制(if/else、for/range、switch、goto、break、continue)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/u014597198/article/details/103270964文章目录0、唠唠叨叨1、分支结构(if / else)1.1、标准写法1.2、特殊写法2、循环结…...

    2024/4/25 13:10:27
  4. 17套vue.js视频教程2套webpack 4套react native

    2019-5-21 新增加10套视频教程:vue2.5实战项目源码vue app开发课程源代码前端...

    2024/4/20 11:41:59
  5. hive优化

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/qq_37554565/article/details/103277434hive的查询注意事项以及优化总结 . Hive是将符合SQL语法的字符串解析生成可以在Had…...

    2024/4/18 11:05:58
  6. 2019-11-27-WPF-全屏透明窗口

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/lindexi_gd/article/details/103277487titleauthordateCreateTimecategoriesWPF 全屏透明窗口lindexi2019-11-27 09:22:19 …...

    2024/4/27 0:32:39
  7. PHP 注释规范

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/owenzhang24/article/details/103277255PHP 注释规范 注释在写代码的过程中非常重要,好的注释能让你的代码读起来更轻松,…...

    2024/4/23 17:36:09
  8. [算法系列之十九]最长公共子序列

    原文链接:https://blog.csdn.net/weixin_34162629/article/details/90688042题目最长公共子序列分析有两个字符串S1和S2,求一个最长公共子串,即求字符串S3,它们同时是S1和S2的子串,且要求它们的长度最长,并确定这个长度。这个问题我们称之为最长公共子序列问题。 与求最…...

    2024/4/20 23:26:14
  9. hadoop的shell操作命令

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/xiaoyaGrace/article/details/1032767761.hadoop fs -setrep 3 / 修改 (/ 根目录下)原来所有文件的副本为3 …...

    2024/4/20 2:08:57
  10. 读写分离很难吗?springboot结合aop简单就实现了

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/ling_76539446/article/details/103276807目录 前言 环境部署 开始项目 注意 參考: 前言 入职新公司到现在也有一个月了,…...

    2024/4/25 15:06:03
  11. 基于web的统计平台开发笔记--1

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/awangdea99/article/details/103276125前言最近接到一项中长期任务,开发一个web统计平台。需求分析和界面图设计本人已初步…...

    2024/4/26 17:45:12
  12. es中常用查询

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/goxingman/article/details/103276225传入keyword查询字段概念termquery不分词不分词准确匹配terms不分词(可传入多个词条…...

    2024/4/23 16:16:11
  13. PLC与上位机的socket通讯——上位机C#程序(二)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/w93509450/article/details/103276447C#的网口通信 一、 命令行 客户端程序: using System; using System.Collections.Gen…...

    2024/4/25 22:45:11
  14. VSCode C++ Debug

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/jsjxm1984/article/details/103276486windows平台:在launch.json中添加{"name": "(Windows) 启动",&…...

    2024/4/20 22:31:02
  15. 电子黄金十年,中国仅有半只脚迈出了富士康

    iFeng科技凤凰网科技官方账号,带你直击真相来源 | 远川科技评论(id:kechuangych)作者 | 陈二营长2009年对中国电子产业来说,是一个特殊的起点,有三件重要的事情发生。第一件,iPhone发行第3代,智能手机市场的彻底引爆只剩一步之遥;第二件,金融危机下的全球电子巨头,开…...

    2024/4/25 8:59:01
  16. 对讲机频率怎么调?四步教你给对讲机调频

    频率相同是两部对讲机可以通话的前提,很多人认为只要两台对讲机是相同品牌的就可以通话,其实不然,如果不在同一个频率,即使相同品牌、相同型号的对讲机也是无法通话的;如果频率相同,即使不是同品牌的对讲机也可以通话,所以,对讲机频率怎么调就很重要了。一般来说,手持…...

    2024/4/18 4:38:54
  17. 来了,“携号转网”正式启动,全国推行!你想转到哪家?

    来源:华尔街见闻(ID:wallstreetcn)位宇祥,文中观点不构成投资建议。11月27日,工信部召开携号转网启动仪式,27日起,携号转网正式在全国提供服务。用户号码保持不变,符合条件可自由选择移动、联通、电信等运营商。电信业务经营者不得干涉用户自主选择。工信部信息通信管…...

    2024/4/26 21:43:24
  18. 2020 IEEE Fellow名单出炉:华人近三成,叶杰平、张潼、周博文、熊辉等AI大牛入选

    机器之心报道机器之心编辑部今日,IEEE 2020 Fellow 当选名单公布,据统计,共有 280 多人当选,其中华人占比近三成,熊辉、叶杰平、张潼、周伯文等知名 AI 科学家当选。IEEE 全称是美国电子电气工程师学会(Institute of Electrical and Electronic Engineers),是国际性电子…...

    2024/4/26 13:11:13
  19. 总线技术基础知识详解(上)

    总线,英文叫作“BUS”,即我们中文的“公共车”,这是非常形象的比喻。公共车走的路线是一定的,我们任何人都可以坐公共车去该条公共车路线的任意一个站点。如果把我们人比作是电子信号,这就是为什么英文叫它为“BUS”而不是“CAR”的真正用意。当然,从专业上来说,总线是一…...

    2024/4/25 19:23:35
  20. mysql 索引(一)

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 本文链接:https://blog.csdn.net/u014207606/article/details/103275687提到数据库索引,我想你并不陌生,在日常工作中会经常接触到。比如某一个 SQL 查询比…...

    2024/4/26 14:08:29

最新文章

  1. VTK----VTK数据结构详解3(代码篇)

    上篇文章&#xff08;VTK----VTK数据结构详解&#xff08;计算机篇&#xff09;-CSDN博客&#xff09;从计算机数据结构&#xff08;数组、链表等&#xff09;的角度对数据数组、数据对象、数据属性的实现原理进行了说明&#xff0c;下面从代码的层面详细说明它们的使用及相关实…...

    2024/4/27 2:12:12
  2. 梯度消失和梯度爆炸的一些处理方法

    在这里是记录一下梯度消失或梯度爆炸的一些处理技巧。全当学习总结了如有错误还请留言&#xff0c;在此感激不尽。 权重和梯度的更新公式如下&#xff1a; w w − η ⋅ ∇ w w w - \eta \cdot \nabla w ww−η⋅∇w 个人通俗的理解梯度消失就是网络模型在反向求导的时候出…...

    2024/3/20 10:50:27
  3. 嵌入式硬件中常见的面试问题与实现

    1 01 请列举您知道的电阻、电容、电感品牌(最好包括国内、国外品牌) ▶电阻 美国:AVX、VISHAY威世 日本:KOA兴亚、Kyocera京瓷、muRata村田、Panasonic松下、ROHM罗姆、susumu、TDK 台湾:LIZ丽智、PHYCOM飞元、RALEC旺诠、ROYALOHM厚生、SUPEROHM美隆、TA-I大毅、TMT…...

    2024/4/26 3:46:10
  4. OpenHarmony实战:Combo解决方案之ASR芯片移植案例

    本方案基于 OpenHarmony LiteOS-M 内核&#xff0c;使用 ASR582X 芯片的 DEV.WIFI.A 开发板进行开发移植。作为典型的 IOT Combo&#xff08;Wi-FiBLE&#xff09;解决方案&#xff0c;本文章介绍 ASR582X 的适配过程。 编译移植 目录规划 本方案的目录结构使用 Board 和 So…...

    2024/4/24 10:50:46
  5. 【外汇早评】美通胀数据走低,美元调整

    原标题:【外汇早评】美通胀数据走低,美元调整昨日美国方面公布了新一期的核心PCE物价指数数据,同比增长1.6%,低于前值和预期值的1.7%,距离美联储的通胀目标2%继续走低,通胀压力较低,且此前美国一季度GDP初值中的消费部分下滑明显,因此市场对美联储后续更可能降息的政策…...

    2024/4/26 18:09:39
  6. 【原油贵金属周评】原油多头拥挤,价格调整

    原标题:【原油贵金属周评】原油多头拥挤,价格调整本周国际劳动节,我们喜迎四天假期,但是整个金融市场确实流动性充沛,大事频发,各个商品波动剧烈。美国方面,在本周四凌晨公布5月份的利率决议和新闻发布会,维持联邦基金利率在2.25%-2.50%不变,符合市场预期。同时美联储…...

    2024/4/26 20:12:18
  7. 【外汇周评】靓丽非农不及疲软通胀影响

    原标题:【外汇周评】靓丽非农不及疲软通胀影响在刚结束的周五,美国方面公布了新一期的非农就业数据,大幅好于前值和预期,新增就业重新回到20万以上。具体数据: 美国4月非农就业人口变动 26.3万人,预期 19万人,前值 19.6万人。 美国4月失业率 3.6%,预期 3.8%,前值 3…...

    2024/4/26 23:05:52
  8. 【原油贵金属早评】库存继续增加,油价收跌

    原标题:【原油贵金属早评】库存继续增加,油价收跌周三清晨公布美国当周API原油库存数据,上周原油库存增加281万桶至4.692亿桶,增幅超过预期的74.4万桶。且有消息人士称,沙特阿美据悉将于6月向亚洲炼油厂额外出售更多原油,印度炼油商预计将每日获得至多20万桶的额外原油供…...

    2024/4/25 18:39:23
  9. 【外汇早评】日本央行会议纪要不改日元强势

    原标题:【外汇早评】日本央行会议纪要不改日元强势近两日日元大幅走强与近期市场风险情绪上升,避险资金回流日元有关,也与前一段时间的美日贸易谈判给日本缓冲期,日本方面对汇率问题也避免继续贬值有关。虽然今日早间日本央行公布的利率会议纪要仍然是支持宽松政策,但这符…...

    2024/4/25 18:39:22
  10. 【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响

    原标题:【原油贵金属早评】欧佩克稳定市场,填补伊朗问题的影响近日伊朗局势升温,导致市场担忧影响原油供给,油价试图反弹。此时OPEC表态稳定市场。据消息人士透露,沙特6月石油出口料将低于700万桶/日,沙特已经收到石油消费国提出的6月份扩大出口的“适度要求”,沙特将满…...

    2024/4/25 18:39:22
  11. 【外汇早评】美欲与伊朗重谈协议

    原标题:【外汇早评】美欲与伊朗重谈协议美国对伊朗的制裁遭到伊朗的抗议,昨日伊朗方面提出将部分退出伊核协议。而此行为又遭到欧洲方面对伊朗的谴责和警告,伊朗外长昨日回应称,欧洲国家履行它们的义务,伊核协议就能保证存续。据传闻伊朗的导弹已经对准了以色列和美国的航…...

    2024/4/26 21:56:58
  12. 【原油贵金属早评】波动率飙升,市场情绪动荡

    原标题:【原油贵金属早评】波动率飙升,市场情绪动荡因中美贸易谈判不安情绪影响,金融市场各资产品种出现明显的波动。随着美国与中方开启第十一轮谈判之际,美国按照既定计划向中国2000亿商品征收25%的关税,市场情绪有所平复,已经开始接受这一事实。虽然波动率-恐慌指数VI…...

    2024/4/25 16:48:44
  13. 【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试

    原标题:【原油贵金属周评】伊朗局势升温,黄金多头跃跃欲试美国和伊朗的局势继续升温,市场风险情绪上升,避险黄金有向上突破阻力的迹象。原油方面稍显平稳,近期美国和OPEC加大供给及市场需求回落的影响,伊朗局势并未推升油价走强。近期中美贸易谈判摩擦再度升级,美国对中…...

    2024/4/26 16:00:35
  14. 【原油贵金属早评】市场情绪继续恶化,黄金上破

    原标题:【原油贵金属早评】市场情绪继续恶化,黄金上破周初中国针对于美国加征关税的进行的反制措施引发市场情绪的大幅波动,人民币汇率出现大幅的贬值动能,金融市场受到非常明显的冲击。尤其是波动率起来之后,对于股市的表现尤其不安。隔夜美国股市出现明显的下行走势,这…...

    2024/4/25 18:39:16
  15. 【外汇早评】美伊僵持,风险情绪继续升温

    原标题:【外汇早评】美伊僵持,风险情绪继续升温昨日沙特两艘油轮再次发生爆炸事件,导致波斯湾局势进一步恶化,市场担忧美伊可能会出现摩擦生火,避险品种获得支撑,黄金和日元大幅走强。美指受中美贸易问题影响而在低位震荡。继5月12日,四艘商船在阿联酋领海附近的阿曼湾、…...

    2024/4/25 18:39:16
  16. 【原油贵金属早评】贸易冲突导致需求低迷,油价弱势

    原标题:【原油贵金属早评】贸易冲突导致需求低迷,油价弱势近日虽然伊朗局势升温,中东地区几起油船被袭击事件影响,但油价并未走高,而是出于调整结构中。由于市场预期局势失控的可能性较低,而中美贸易问题导致的全球经济衰退风险更大,需求会持续低迷,因此油价调整压力较…...

    2024/4/26 19:03:37
  17. 氧生福地 玩美北湖(上)——为时光守候两千年

    原标题:氧生福地 玩美北湖(上)——为时光守候两千年一次说走就走的旅行,只有一张高铁票的距离~ 所以,湖南郴州,我来了~ 从广州南站出发,一个半小时就到达郴州西站了。在动车上,同时改票的南风兄和我居然被分到了一个车厢,所以一路非常愉快地聊了过来。 挺好,最起…...

    2024/4/26 22:01:59
  18. 氧生福地 玩美北湖(中)——永春梯田里的美与鲜

    原标题:氧生福地 玩美北湖(中)——永春梯田里的美与鲜一觉醒来,因为大家太爱“美”照,在柳毅山庄去寻找龙女而错过了早餐时间。近十点,向导坏坏还是带着饥肠辘辘的我们去吃郴州最富有盛名的“鱼头粉”。说这是“十二分推荐”,到郴州必吃的美食之一。 哇塞!那个味美香甜…...

    2024/4/25 18:39:14
  19. 氧生福地 玩美北湖(下)——奔跑吧骚年!

    原标题:氧生福地 玩美北湖(下)——奔跑吧骚年!让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 让我们红尘做伴 活得潇潇洒洒 策马奔腾共享人世繁华 对酒当歌唱出心中喜悦 轰轰烈烈把握青春年华 啊……啊……啊 两…...

    2024/4/26 23:04:58
  20. 扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!

    原标题:扒开伪装医用面膜,翻六倍价格宰客,小姐姐注意了!扒开伪装医用面膜,翻六倍价格宰客!当行业里的某一品项火爆了,就会有很多商家蹭热度,装逼忽悠,最近火爆朋友圈的医用面膜,被沾上了污点,到底怎么回事呢? “比普通面膜安全、效果好!痘痘、痘印、敏感肌都能用…...

    2024/4/25 2:10:52
  21. 「发现」铁皮石斛仙草之神奇功效用于医用面膜

    原标题:「发现」铁皮石斛仙草之神奇功效用于医用面膜丽彦妆铁皮石斛医用面膜|石斛多糖无菌修护补水贴19大优势: 1、铁皮石斛:自唐宋以来,一直被列为皇室贡品,铁皮石斛生于海拔1600米的悬崖峭壁之上,繁殖力差,产量极低,所以古代仅供皇室、贵族享用 2、铁皮石斛自古民间…...

    2024/4/25 18:39:00
  22. 丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者

    原标题:丽彦妆\医用面膜\冷敷贴轻奢医学护肤引导者【公司简介】 广州华彬企业隶属香港华彬集团有限公司,专注美业21年,其旗下品牌: 「圣茵美」私密荷尔蒙抗衰,产后修复 「圣仪轩」私密荷尔蒙抗衰,产后修复 「花茵莳」私密荷尔蒙抗衰,产后修复 「丽彦妆」专注医学护…...

    2024/4/26 19:46:12
  23. 广州械字号面膜生产厂家OEM/ODM4项须知!

    原标题:广州械字号面膜生产厂家OEM/ODM4项须知!广州械字号面膜生产厂家OEM/ODM流程及注意事项解读: 械字号医用面膜,其实在我国并没有严格的定义,通常我们说的医美面膜指的应该是一种「医用敷料」,也就是说,医用面膜其实算作「医疗器械」的一种,又称「医用冷敷贴」。 …...

    2024/4/25 18:38:58
  24. 械字号医用眼膜缓解用眼过度到底有无作用?

    原标题:械字号医用眼膜缓解用眼过度到底有无作用?医用眼膜/械字号眼膜/医用冷敷眼贴 凝胶层为亲水高分子材料,含70%以上的水分。体表皮肤温度传导到本产品的凝胶层,热量被凝胶内水分子吸收,通过水分的蒸发带走大量的热量,可迅速地降低体表皮肤局部温度,减轻局部皮肤的灼…...

    2024/4/25 18:38:57
  25. 配置失败还原请勿关闭计算机,电脑开机屏幕上面显示,配置失败还原更改 请勿关闭计算机 开不了机 这个问题怎么办...

    解析如下&#xff1a;1、长按电脑电源键直至关机&#xff0c;然后再按一次电源健重启电脑&#xff0c;按F8健进入安全模式2、安全模式下进入Windows系统桌面后&#xff0c;按住“winR”打开运行窗口&#xff0c;输入“services.msc”打开服务设置3、在服务界面&#xff0c;选中…...

    2022/11/19 21:17:18
  26. 错误使用 reshape要执行 RESHAPE,请勿更改元素数目。

    %读入6幅图像&#xff08;每一幅图像的大小是564*564&#xff09; f1 imread(WashingtonDC_Band1_564.tif); subplot(3,2,1),imshow(f1); f2 imread(WashingtonDC_Band2_564.tif); subplot(3,2,2),imshow(f2); f3 imread(WashingtonDC_Band3_564.tif); subplot(3,2,3),imsho…...

    2022/11/19 21:17:16
  27. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机...

    win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”问题的解决方法在win7系统关机时如果有升级系统的或者其他需要会直接进入一个 等待界面&#xff0c;在等待界面中我们需要等待操作结束才能关机&#xff0c;虽然这比较麻烦&#xff0c;但是对系统进行配置和升级…...

    2022/11/19 21:17:15
  28. 台式电脑显示配置100%请勿关闭计算机,“准备配置windows 请勿关闭计算机”的解决方法...

    有不少用户在重装Win7系统或更新系统后会遇到“准备配置windows&#xff0c;请勿关闭计算机”的提示&#xff0c;要过很久才能进入系统&#xff0c;有的用户甚至几个小时也无法进入&#xff0c;下面就教大家这个问题的解决方法。第一种方法&#xff1a;我们首先在左下角的“开始…...

    2022/11/19 21:17:14
  29. win7 正在配置 请勿关闭计算机,怎么办Win7开机显示正在配置Windows Update请勿关机...

    置信有很多用户都跟小编一样遇到过这样的问题&#xff0c;电脑时发现开机屏幕显现“正在配置Windows Update&#xff0c;请勿关机”(如下图所示)&#xff0c;而且还需求等大约5分钟才干进入系统。这是怎样回事呢&#xff1f;一切都是正常操作的&#xff0c;为什么开时机呈现“正…...

    2022/11/19 21:17:13
  30. 准备配置windows 请勿关闭计算机 蓝屏,Win7开机总是出现提示“配置Windows请勿关机”...

    Win7系统开机启动时总是出现“配置Windows请勿关机”的提示&#xff0c;没过几秒后电脑自动重启&#xff0c;每次开机都这样无法进入系统&#xff0c;此时碰到这种现象的用户就可以使用以下5种方法解决问题。方法一&#xff1a;开机按下F8&#xff0c;在出现的Windows高级启动选…...

    2022/11/19 21:17:12
  31. 准备windows请勿关闭计算机要多久,windows10系统提示正在准备windows请勿关闭计算机怎么办...

    有不少windows10系统用户反映说碰到这样一个情况&#xff0c;就是电脑提示正在准备windows请勿关闭计算机&#xff0c;碰到这样的问题该怎么解决呢&#xff0c;现在小编就给大家分享一下windows10系统提示正在准备windows请勿关闭计算机的具体第一种方法&#xff1a;1、2、依次…...

    2022/11/19 21:17:11
  32. 配置 已完成 请勿关闭计算机,win7系统关机提示“配置Windows Update已完成30%请勿关闭计算机”的解决方法...

    今天和大家分享一下win7系统重装了Win7旗舰版系统后&#xff0c;每次关机的时候桌面上都会显示一个“配置Windows Update的界面&#xff0c;提示请勿关闭计算机”&#xff0c;每次停留好几分钟才能正常关机&#xff0c;导致什么情况引起的呢&#xff1f;出现配置Windows Update…...

    2022/11/19 21:17:10
  33. 电脑桌面一直是清理请关闭计算机,windows7一直卡在清理 请勿关闭计算机-win7清理请勿关机,win7配置更新35%不动...

    只能是等着&#xff0c;别无他法。说是卡着如果你看硬盘灯应该在读写。如果从 Win 10 无法正常回滚&#xff0c;只能是考虑备份数据后重装系统了。解决来方案一&#xff1a;管理员运行cmd&#xff1a;net stop WuAuServcd %windir%ren SoftwareDistribution SDoldnet start WuA…...

    2022/11/19 21:17:09
  34. 计算机配置更新不起,电脑提示“配置Windows Update请勿关闭计算机”怎么办?

    原标题&#xff1a;电脑提示“配置Windows Update请勿关闭计算机”怎么办&#xff1f;win7系统中在开机与关闭的时候总是显示“配置windows update请勿关闭计算机”相信有不少朋友都曾遇到过一次两次还能忍但经常遇到就叫人感到心烦了遇到这种问题怎么办呢&#xff1f;一般的方…...

    2022/11/19 21:17:08
  35. 计算机正在配置无法关机,关机提示 windows7 正在配置windows 请勿关闭计算机 ,然后等了一晚上也没有关掉。现在电脑无法正常关机...

    关机提示 windows7 正在配置windows 请勿关闭计算机 &#xff0c;然后等了一晚上也没有关掉。现在电脑无法正常关机以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;关机提示 windows7 正在配…...

    2022/11/19 21:17:05
  36. 钉钉提示请勿通过开发者调试模式_钉钉请勿通过开发者调试模式是真的吗好不好用...

    钉钉请勿通过开发者调试模式是真的吗好不好用 更新时间:2020-04-20 22:24:19 浏览次数:729次 区域: 南阳 > 卧龙 列举网提醒您:为保障您的权益,请不要提前支付任何费用! 虚拟位置外设器!!轨迹模拟&虚拟位置外设神器 专业用于:钉钉,外勤365,红圈通,企业微信和…...

    2022/11/19 21:17:05
  37. 配置失败还原请勿关闭计算机怎么办,win7系统出现“配置windows update失败 还原更改 请勿关闭计算机”,长时间没反应,无法进入系统的解决方案...

    前几天班里有位学生电脑(windows 7系统)出问题了&#xff0c;具体表现是开机时一直停留在“配置windows update失败 还原更改 请勿关闭计算机”这个界面&#xff0c;长时间没反应&#xff0c;无法进入系统。这个问题原来帮其他同学也解决过&#xff0c;网上搜了不少资料&#x…...

    2022/11/19 21:17:04
  38. 一个电脑无法关闭计算机你应该怎么办,电脑显示“清理请勿关闭计算机”怎么办?...

    本文为你提供了3个有效解决电脑显示“清理请勿关闭计算机”问题的方法&#xff0c;并在最后教给你1种保护系统安全的好方法&#xff0c;一起来看看&#xff01;电脑出现“清理请勿关闭计算机”在Windows 7(SP1)和Windows Server 2008 R2 SP1中&#xff0c;添加了1个新功能在“磁…...

    2022/11/19 21:17:03
  39. 请勿关闭计算机还原更改要多久,电脑显示:配置windows更新失败,正在还原更改,请勿关闭计算机怎么办...

    许多用户在长期不使用电脑的时候&#xff0c;开启电脑发现电脑显示&#xff1a;配置windows更新失败&#xff0c;正在还原更改&#xff0c;请勿关闭计算机。。.这要怎么办呢&#xff1f;下面小编就带着大家一起看看吧&#xff01;如果能够正常进入系统&#xff0c;建议您暂时移…...

    2022/11/19 21:17:02
  40. 还原更改请勿关闭计算机 要多久,配置windows update失败 还原更改 请勿关闭计算机,电脑开机后一直显示以...

    配置windows update失败 还原更改 请勿关闭计算机&#xff0c;电脑开机后一直显示以以下文字资料是由(历史新知网www.lishixinzhi.com)小编为大家搜集整理后发布的内容&#xff0c;让我们赶快一起来看一下吧&#xff01;配置windows update失败 还原更改 请勿关闭计算机&#x…...

    2022/11/19 21:17:01
  41. 电脑配置中请勿关闭计算机怎么办,准备配置windows请勿关闭计算机一直显示怎么办【图解】...

    不知道大家有没有遇到过这样的一个问题&#xff0c;就是我们的win7系统在关机的时候&#xff0c;总是喜欢显示“准备配置windows&#xff0c;请勿关机”这样的一个页面&#xff0c;没有什么大碍&#xff0c;但是如果一直等着的话就要两个小时甚至更久都关不了机&#xff0c;非常…...

    2022/11/19 21:17:00
  42. 正在准备配置请勿关闭计算机,正在准备配置windows请勿关闭计算机时间长了解决教程...

    当电脑出现正在准备配置windows请勿关闭计算机时&#xff0c;一般是您正对windows进行升级&#xff0c;但是这个要是长时间没有反应&#xff0c;我们不能再傻等下去了。可能是电脑出了别的问题了&#xff0c;来看看教程的说法。正在准备配置windows请勿关闭计算机时间长了方法一…...

    2022/11/19 21:16:59
  43. 配置失败还原请勿关闭计算机,配置Windows Update失败,还原更改请勿关闭计算机...

    我们使用电脑的过程中有时会遇到这种情况&#xff0c;当我们打开电脑之后&#xff0c;发现一直停留在一个界面&#xff1a;“配置Windows Update失败&#xff0c;还原更改请勿关闭计算机”&#xff0c;等了许久还是无法进入系统。如果我们遇到此类问题应该如何解决呢&#xff0…...

    2022/11/19 21:16:58
  44. 如何在iPhone上关闭“请勿打扰”

    Apple’s “Do Not Disturb While Driving” is a potentially lifesaving iPhone feature, but it doesn’t always turn on automatically at the appropriate time. For example, you might be a passenger in a moving car, but your iPhone may think you’re the one dri…...

    2022/11/19 21:16:57