第一行代码-活动的生存周期

来源:互联网 发布:复制淘宝店铺违规吗 编辑:程序博客网 时间:2024/05/23 01:14

1.返回栈

Android是使用任务(Task)来管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈被称作返回栈(back Stack)。栈是一种先进先出的数据结构。

每当启动了一个新的活动,会在返回栈中入栈,并处于栈顶的位置,使用Back键或调用finish()方法销毁一个活动时,处于栈顶的活动会出栈,这时前一个入栈

的活动就会处于栈顶的位置。系统会显示处于栈顶位置的活动给用户。

2.活动状态

每个活动在其生命周期最多会有四种状态。

1.运行状态

活动位于返回栈的栈顶位置,活动就能够处于运行状态。系统最不愿意回收的就是处于运行状态的活动。

2.暂停状态

活动不处于栈顶位置,仍然可见,活动就进入了暂停状态。并不是每一个活动都会占满整个屏幕。

3.停止状态

活动部处于栈顶位置,并且完全不可见的时候,就进入了停止状态。

4.销毁状态

活动从返回栈中移除后,就变成了销毁状态,系统倾向于回收处于这种状态的活动,从而保证手机的内存充足。

3.活动的生存期

Activity类定义了7个回调方法,覆盖了活动生命周期的每个环节。

*onCreate()。活动第一次创建的时候调用。在这个方法中完成活动的初始化操作。比如加载布局、绑定事件等。

*onStart()。活动由不可见变为可见时调用。

*onResume().在活动准备好和用户进行交互的时候调用。此时的活动位于返回栈的栈顶,并且处于运行状态。

*onPause().系统准备去启动或者恢复另一个活动的时候调用。在这个方法中将一些消耗CPU的资源释放掉,以及保存一

些关键数据,这个方法的执行速度要快,不然会影响栈顶活动的使用。

*onStop()。活动完全不可见的时候调用。它和onPause的区别是,如果启动的新活动是一个对话框式的活动,那么onPause()方法

会得到执行。而onStop()方法并不会执行。

*onDestroy().在活动销毁前调用,之后活动的状态变为销毁状态。

*onRestart()。活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。

活动可以分为3种生存周期。

*完整生存期。 活动在onCreate()方法和onDestroy()方法之间经历的就是完整生存周期。活动在onCreate()方法中完成各种初始化操作。

而onDestroy()方法中完成释放内存的操作。

*可见生存期。活动在onStart()方法和onStop()方法之间经历的就是可见生存期。在可见生存期内,活动是可见的,在onStart()方法中对

资源进行加载,在onStop()方法内对资源进行释放。从而保证处于停止状态的活动不会占用过多内存。

*前台生存期。活动在onResume()方法和onPause方法之间所经历的就是前台生存期.在前台生存期内,活动是处于运行状态的。此时的活动

可以和用户进行交互。




当Main活动第一次被创建时会依次执行onCreate()、onStart()和onResume()方法。Main活动通过intent启动second活动,将Main活动完全遮挡住,onPause()

和onStop()方法都会得到执行。按下back键返回Main活动时,onRestart()方法会得到执行,然后依次执行onStart()和onResume()方法。注意此时的onCreate()方法

不会执行,因为Main活动没有得到创建。这时启动一个对话框,Main活动没有被完全遮挡,只有onPause()方法得到了执行,onStop()方法没有执行。最后按下back键

退出程序,onPause()、onStop()和onDestroy()方法会依次得到执行。最终销毁Main活动。

4.活动被回收

如果活动进入了停止状态,有可能被系统回收。那么活动中是可能存在临时数据区和状态的就可能会丢失。Activity中提供了一个onSaveInstance()回调方法。这个

回调方法会保证活动被回收之前调用。通过这个方法可以解决活动被回收时临时数据得不到保存的问题。

onSaveInstance()方法带一个Bundle类型的参数,Bundle提供了方法用于保存数据,比如putString()方法保存字符串、使用putInt()方法保存整型数据,以此类推。

每个保存方法需要传入两个参数,第一个参数是键,用于后面从Bundle中取值,第二个参数是保存的内容。

    @Override    protected void onSaveInstanceState(Bundle outState) {        super.onSaveInstanceState(outState);        String tempData = "sommthinng you just typed";        outState.putString("data_key",tempData);    }

字符串数据tempData已经保存了,如果活动在被系统回收前通过onSaveInstanceState()方法来保存数据,onCreate()方法中的参数Bundle就会带有之前保存

的全部数据,只需要通过相应的取值方法将数据取出。

    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        if(savedInstanceState != null)        {            String tempData = savedInstanceState.getString("data_key");        }    }
将保存的数据取出后在重新恢复给活动就可以了。Bundle保存数据和取出数据的方法和Intent传递数据使用的是类似的方法。

Intent方法还可以结合Bundle一起用于传递数据。首先可以把数据保存在Bundle对象中,然后再将Bundle对象存放在Intent中。到了目标活动再从Intent中

取出Bundle对象,再从Bundle中一一取出数据。

5.活动的启动模式

活动有四种启动模式,分别是standard、singleTop、singleTask和singleInstance。可以在AndroidManifest.xml中通过<activity>标签

指定android:launchMode属性来选择启动模式.

5.1 standard

standard是活动默认的启动模式,在不进行显示指定的情况下,所有的活动都会自动使用这种模式。Android使用返回栈来管理活动的,每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置,使用standard模式的活动,系统不论活动是否在返回栈中存在,每次启动都会创建一个新的实例。

5.2 singleTop

当活动的启动模式是singleTop,那么启动活动的时候如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的 活动实例。

在AndroidManifest.xml标签内修改MainActivity的启动模式为singleTop。

        <activity android:name=".MainActivity"                android:lunchMode="singleTop">            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>
当MainActivity处于返回栈栈顶位置时,每一次启动MainActivity时都会直接使用栈顶的活动,因此MainActivity只会有一个实例。只按一次Back键就可以退出程序。

当MainActivity并未处于栈顶位置时,再启动MainActivity还是会创建新的实例的。

singleTop模式的示意原理图如下:

5.3 singleTask

当活动指定为singleTask,每次启动活动都会检查返回栈中是否存在该活动的实例,如果存在则直接使用该实例,并把这个活动之上的所有活动全部出栈,

如果没有则创建一个新的活动实例。

指定活动的启动模式为singleTask。

        <activity            android:lunchMode="singleTask"            android:name=".MainActivity"               >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>

在SecondActivity中启动FirstActivity时,会发现返回栈中已经存在了一个FirstActivity的实例,并且在SecondActivity的下面,于是SecondActivity会从返回栈中出栈,而FirstActivity

重新成为了栈顶活动。因此FirstActivity的onRestart()方法和SecondActivity的onDestroy()方法会得到执行。

singleTask的示意图如下:


5.4 singleInstance

  指定为singleInstance模式的活动会启用一个新的返回栈来管理这个活动。如果程序中有一个活动可以允许其他程序调用,使用能够前面的三种启动模式无法

实现。因为每个应用程序都有自己的返回栈,同一个活动在不同的返回栈中入栈时必然是创建了新的实例。而使用singleInstance模式可以有一个单独的返回栈来管理活动。

这样不论哪个应用程序来访问这个活动都共用一个返回栈,也就实现了共享活动。

在AndroidManifest.xml中修改启动模式为singleInstance

       <activity            android:lunchMode="singleInstance"            android:name=".MainActivity"               >            <intent-filter>                <action android:name="android.intent.action.MAIN" />                <category android:name="android.intent.category.LAUNCHER" />            </intent-filter>        </activity>
 使SecondActivity的启动模式为singleInstance.singleInstance模式的原理示意图如下:


6.活动的实践

6.1知晓当前是哪一个活动

能程序根据程序的当前界面判断出是哪一个活动。创建一个BaseActivity类继承自AppCompatActivity类,并且重写onCreate()方法。
如下所示:
public class BaseActivity extends AppCompatActivity {    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        Log.d("BaseActivity", getClass().getSimpleName());    }}
在onCreate()方法中获取了当前实例的类名,并通过Log打印了出来。
接下来使程序中的所有活动继承自BaseActivity。使FirstActivity、SecondActivity和ThirdActivity都继承自BaseActivity.重新运行程序,程序的活动功能不受影响
每当进入到一个活动的界面,该活动的类名就会被打印出来.

6.2 随时随地退出程序

如果程序中启动了太多活动,在返回栈中有太多活动入栈,在当前的活动(栈顶的活动)退出程序是非常不方便的 。需要连续按Backed键退出,将活动从返回栈

中出栈。按HOME键只是把程序挂起。可以通过一个专门的集合类来对所有的活动进行管理,进而实现一个注销或者退出的功能。

新建一个ActivityCollector类作为活动管理器。

public class ActivityCollector {    public  static  ArrayList<Activity> sActivityListies = new ArrayList<>();    public  static  void  addActivity(Activity activity)    {        sActivityListies.add(activity);    }    public  static  void  removeActivity(Activity activity)    {        sActivityListies.remove(activity);    }    public  static  void  finishAll()    {        for(Activity activity:sActivityListies)        {            if (!activity.isFinishing()) {                activity.finish();            }        }    }}

在活动管理器中通过一个List来管理活动,然后提供了一个addActivity()方法用于向List中添加活动,提供了一个removeActivity()方法用于从List中移除活动,最后提供了一个finishAll()方法用于将List中存储的活动全部销毁。

接下来修改BaseAcitivity中的代码。如下所示:

    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        super.onCreate(savedInstanceState);        Log.d("BaseActivity", getClass().getSimpleName());        ActivityCollector.addActivity(this);    }    @Override    protected void onDestroy() {        super.onDestroy();        ActivityCollector.removeActivity(this);    }

在BaseAcitivity的onCreate()方法中调用了ActivityCollector的addActivity()方法表明当前正在创建的活动添加到活动管理器。然后在BaseActivity中重写

onDestroy()方法,并且调用了AcitivityCollector的removeActivity()方法,表明将马上一个马上要销毁的活动从活动管理器中移除。

从此想要退出程序只需要调用ActivityCollector.finishAll()方法就可以了。

可以在销毁活动的代码后面加上杀掉当前进程的代码,保证程序完全退出。杀掉进程的代码如下:

 android.os.Process.killProcess(android.os.Process.myPid);
killProcess()方法用于杀掉一个进程,他接收一个进程的id参数,可以通过myPid()方法来获取当前程序的进程id。需要注意的是killProcess()方法只能

用于杀掉当前程序的进程,不能使用这个方法杀掉其他程序。

6.3启动活动的最佳写法

通过在SecondActivity活动中添加actionStart()方法,在这个方法中完成了Intent的构建,另外所有SecondActivity中需要的数据都通过actionStart()方法的参数

传递过来。然后存储到Intent中,最后通过startActivity()方法启动

        public  static  void  actionStart(Context context, String data1, String data2)        {            Intent intent = new Intent(context, SecondActivity.class);            intent.putExtra("param1", data1);            intent.putExtra("param2",data2);            context.startActivity(intent);        }