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

Android起航——四大组件之Activity(一)_第1张图片
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)


Android起航——四大组件之Activity(一)_第2张图片
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指定启动模式


另一种是通过在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= 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(一))