美文网首页
Android起航——四大组件之Activity(一)

Android起航——四大组件之Activity(一)

作者: kevenZheng | 来源:发表于2018-03-27 17:08 被阅读0次
    image

    一、Activity生命周期方法:

    onCreate():表示Activity刚被创建,会在此方法中使用一些初始化数据操作,以及调用setContentView去加载Activity的布局。

    onStart():表示Activity正在被启动,即将开始,这时候的Activity以及变得可见了,只是还不可以和用户进行交互。

    onResume():表示Activity出现在前台,并且以及可以和用户进行交互。

    onPause():表示Activity正在停止,由可见变为不可见的一个过程,紧接着,onStop方法会被调用。

    onStop():表示Activity被停止,出于后台,可以做一些稍微重量级的数据回收,但不可做耗时操作。

    onDestory():表示Activity被销毁,这是Activity的最后一个生命周期,可以这里做一些最后的资源回收,以及释放工作。

    onRestart():表示Activity正在重新启动,紧接着会调用onStart()。

    二、常见异常情况下Activity的生命周期,及数据保存

    1、当Activity进行横竖屏切换的时候,当从竖屏切换到横屏

    
    03-26 18:38:12.727 29363-29363/com.kevenzheng E/keven: onPause()
    
    03-26 18:38:12.727 29363-29363/com.kevenzheng E/keven: onStop()
    
    03-26 18:38:12.727 29363-29363/com.kevenzheng E/keven: onDestory()
    
    03-26 18:38:12.797 29363-29363/com.kevenzheng E/keven: onCreate()
    
    03-26 18:38:12.797 29363-29363/com.kevenzheng E/keven: onStart()
    
    03-26 18:38:12.797 29363-29363/com.kevenzheng E/keven: onRestoreInstanceState()
    
    03-26 18:38:12.797 29363-29363/com.kevenzheng E/keven: onResume()
    
    

    当Activity进行横竖屏切换的时候,当从横屏切换到竖屏:

    
    03-26 18:43:36.057 29363-29363/com.kevenzheng E/keven: onPause()
    
    03-26 18:43:36.057 29363-29363/com.kevenzheng E/keven: onStop()
    
    03-26 18:43:36.057 29363-29363/com.kevenzheng E/keven: onDestory()
    
    03-26 18:43:36.147 29363-29363/com.kevenzheng E/keven: onCreate()
    
    03-26 18:43:36.147 29363-29363/com.kevenzheng E/keven: onStart()
    
    03-26 18:43:36.147 29363-29363/com.kevenzheng E/keven: onRestoreInstanceState()
    
    03-26 18:43:36.147 29363-29363/com.kevenzheng E/keven: onResume()
    
    03-26 18:44:00.227 29363-29363/com.kevenzheng E/keven: onPause()
    
    03-26 18:44:00.227 29363-29363/com.kevenzheng E/keven: onStop()
    
    03-26 18:44:00.227 29363-29363/com.kevenzheng E/keven: onDestory()
    
    03-26 18:44:00.297 29363-29363/com.kevenzheng E/keven: onCreate()
    
    03-26 18:44:00.297 29363-29363/com.kevenzheng E/keven: onStart()
    
    03-26 18:44:00.297 29363-29363/com.kevenzheng E/keven: onRestoreInstanceState()
    
    03-26 18:44:00.297 29363-29363/com.kevenzheng E/keven: onResume()
    
    

    从上面可以看出,当从竖屏切换为横屏的时候,生命周期重新走了一遍,当从横屏切换为竖屏的时候,整个生命周期运行了两遍。
    总结:
    (1)不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次

    (2)设置Activity的android:configChanges="orientation"时,切屏还是会重新调用各个生命周期,切横、竖屏时只会执行一次

    (3)设置Activity的android:configChanges="orientation|screenSize"时,切屏不会重新调用各个生命周期,只会执行onConfigurationChanged方法。(执行这个方法,必须设置sdk version 大于等于13.0)


    image.png

    2、当Activity在后台被GC回收
    会调用onSaveInstanceState()进行数据保存,当Activity重新启动的时候,会调用onRestoreInstanceState()进行数据的恢复工作,需要强调的一点是,只有当Activity是异常结束的时候,才会调用onSaveInstanceState()方法进行数据保存。

    三、Activity的四种启动模式
    在默认情况下,当我们多次启动同一个Activity,系统会重复创建Activity并压入栈顶,任务栈是个“后进先出”的栈结构,每次都创建同一个Activity的实例难免有些问题,所以安卓提供了四种启动模式:standard、singleTop、singleTask和singleInstance,下面先介绍下四种启动模式:
    (1)standard
    标准启动模式,每启动一个Activity都会创建一个新的Activity的实例,standard模式启动的Activity默认会进入到启动它的Activity的任务栈中。
    (2)singleTop
    栈顶复用模式,在这种模式下,如果新的Activity已经存在于栈顶,那么将不会创建此Activity的实例,位于栈顶的Activity将会被复用,并调用onNewIntent方法用于接受当前的请求信息,如果新的Activity并不位于栈顶,那么新的Activity还是会被创建。
    (3)singleTask
    栈内复用模式,如果要启动的Activity已经存在实例在任务栈中,则不会创建新的Activity实例,且会像singleTop一样,调用onNewIntent方法,用于接受当前的请求信息,如果此Activity位于栈顶,则可以直接复用,如果此Activity不是位于栈顶,则位于此Activity上的所有Activity都会出栈,且复用此Activity的实例。
    (4)singleInstance
    单例模式,如果要创建的Activity已经存在,则不会创建新的Activity,否则,则创建一个新的任务栈,并将Activity的实例放入任务栈中。单例模式除了具备singleTask模式的所有特性外,还有一点就是单独位于一个任务栈中。
    那么怎么给Activity指定启动模式呢?具体有两种方法,一种是通过AndroidManifest为Activity指定启动模式

    <activity android:name=".ActivityDemoActivity"
                      android:launchMode="standard"
            >
    

    另一种是通过在Intent中设置标志位来为Activity设置启动模式

    Intent intent=new Intent(this,ActivityDemoActivity.class);
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
    

    四、Activity的启动原理(分析源码)
    首先说下setContentView方法,进行设置布局,通过查看源码:

    @Override
        public void setContentView(@LayoutRes int layoutResID) {
            getDelegate().setContentView(layoutResID);
        }
    

    发现调用了getDelegate的方法,getDelegate方法通过单例模式返回一个AppCompatDelegate对象

    @NonNull
        public AppCompatDelegate getDelegate() {
            if (mDelegate == null) {
                mDelegate = AppCompatDelegate.create(this, this);
            }
            return mDelegate;
        }
    

    AppCompatDelegate是个抽象类,通过它的setContentView方法进行布局的绑定。

    我们都知道,调用startActivity可以启动一个新的Activity,那么究竟是如何启动的呢?

    @Override
        public void startActivity(Intent intent) {
            this.startActivity(intent, null);
        }
    
     @Override
        public void startActivity(Intent intent, @Nullable Bundle options) {
            if (options != null) {
                startActivityForResult(intent, -1, options);
            } else {
                // Note we want to go through this call for compatibility with
                // applications that may have overridden the method.
                startActivityForResult(intent, -1);
            }
        }
    
    public void startActivityForResult(@RequiresPermission Intent intent, int requestCode) {
            startActivityForResult(intent, requestCode, null);
        }
    

    通过上面的代码,我们会发现,调用startActivity的时候,还是调用了startActivityForResult方法,那我们看下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) {
                    // If this start is requesting a result, we can avoid making
                    // the activity visible until the result is received.  Setting
                    // this code during onCreate(Bundle savedInstanceState) or onResume() will keep the
                    // activity hidden during this time, to avoid flickering.
                    // This can only be done when a result is requested because
                    // that guarantees we will get information back when the
                    // activity is finished, no matter what happens to it.
                    mStartedActivity = true;
                }
    
                cancelInputsAndStartExitTransition(options);
                // TODO Consider clearing/flushing other event sources and events for child windows.
            } 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);
                }
            }
        }
    

    其中Instrumentation的execStartActivity方法启动Activity

    public ActivityResult execStartActivity(
                Context who, IBinder contextThread, IBinder token, String resultWho,
                Intent intent, int requestCode, Bundle options, UserHandle user) {
            IApplicationThread whoThread = (IApplicationThread) contextThread;
            if (mActivityMonitors != null) {
                synchronized (mSync) {
                    final int N = mActivityMonitors.size();
                    for (int i=0; i<N; i++) {
                        final ActivityMonitor am = mActivityMonitors.get(i);
                        ActivityResult result = null;
                        if (am.ignoreMatchingSpecificIntents()) {
                            result = am.onStartActivity(intent);
                        }
                        if (result != null) {
                            am.mHits++;
                            return result;
                        } else if (am.match(who, null, intent)) {
                            am.mHits++;
                            if (am.isBlocking()) {
                                return requestCode >= 0 ? am.getResult() : null;
                            }
                            break;
                        }
                    }
                }
            }
            try {
                intent.migrateExtraStreamToClipData();
                intent.prepareToLeaveProcess(who);
                int result = ActivityManager.getService()
                    .startActivityAsUser(whoThread, who.getBasePackageName(), intent,
                            intent.resolveTypeIfNeeded(who.getContentResolver()),
                            token, resultWho,
                            requestCode, 0, null, options, user.getIdentifier());
                checkStartActivityResult(result, intent);
            } catch (RemoteException e) {
                throw new RuntimeException("Failure from system", e);
            }
            return null;
        }
    

    通过查看源码,发现调用的是ActivityManager.getService().startActivityAsUser,而启动的返回则是调用了

    mMainThread.sendActivityResult(
                        mToken, mEmbeddedID, requestCode, ar.getResultCode(),
                        ar.getResultData());
    

    相关文章

      网友评论

          本文标题:Android起航——四大组件之Activity(一)

          本文链接:https://www.haomeiwen.com/subject/duzrcftx.html