此前,重温了一下《android第一行代码》第二版,在这里做个小小的记录。
一、活动周期
返回栈
android是使用任务(Task)管理活动的,一个任务就是一组存放在栈里的活动的集合,这个栈也被称作返回栈(Back Stack)。栈的特点就是后进先出,我们这里的活动也是一样。
活动状态
我们这里根据在栈中所在位置进行判断。
1、运行状态
一个活动位于返回栈的栈顶
2、暂停状态
一个活动不处于栈顶,但依然可见(例如活动只占了一部分屏幕的情形,只有在内存极低的情况下,系统才会考虑回收这种活动)
3、停止状态
一个活动不再处于栈顶,并且完全不可见时(当其他地方需要内存时,处于停止状态的活动有可能会被系统回收)
4、销毁状态
一个活动从返回栈中移除
活动的生存周期
- onCreate():它会在活动第一次被创建的时候调用。在这个方法中完成活动的初始化操作,比如 说加载布局、绑定事件等。
- onStart():这个方法在活动由不可见变为可见的时候调用。
- onResume():这个方法在活动准备好和用户进行交互的时候调用。此时的活动一定位于返回栈的栈顶,并且处于运行状态。
- onPause():这个方法在系统准备去启动或者恢复另一个活动的时候调用。我们通常会在 这个方法中将一些消耗CPU的资源释放掉,以及保存一些关键数据,但这个方法的执行 速度一定要快,不然会影响到新的栈顶活动的使用。
- onStopO:这个方法在活动完全不可见的时候调用。它和0nPauseO方法的主要区别在 于,如果启动的新活动是一个对话框式的活动,那么onPause()方法会得到执行,而 onStopO方法并不会执行。
- onDestroy():这个方法在活动被销毁之前调用,之后活动的状态将变为销毁状态。
- onRestart():这个方法在活动由停止状态变为运行状态之前调用,也就是活动被重新启动了。
以上7个方法中除了 onRestart()方法,其他都是两两相对的,从而又可以将活动分为3 种生存期。
- 完整生存期。活动在onCreateO方法和onDestroyO方法之间所经历的,就是完整生存期。一般情况下,一个活动会在onCreateO方法中完成各种初始化操作,而在 onDestroyO方法中完成释放内存的操作。
- 可见生存期。活动在onStartO方法和onStopO方法之间所经历的,就是可见生存期。 在可见生存期内,活动对于用户总是可见的,即便有可能无法和用户进行交互。我们可 以通过这两个方法,合理地管理那些对用户可见的资源。比如在onStart()方法中对资 源进行加载,而在onStopO方法中对资源进行释放,从而保证处于停止状态的活动不会 占用过多内存。
- 前台生存期。活动在onResumeO方法和onPauseO方法之间所经历的就是前台生存期。 在前台生存期内,活动总是处于运行状态的,此时的活动是可以和用户进行交互的,我 们平时看到和接触最多的也就是这个状态下的活动。
活动回收丢失数据问题
活动在回收前一定会回调onSaveInstanceState()方法。
onSaveInstanceState()方法会携带一个Bundle类型的参数,Bundle提供了一系列的方法用于保存数据,比如可以使用putString()方法保存字符串,使用putlnt()方法保存整型数据,以键值对保存。
在MainActivity中添加如下代码就可以将临时数据进行保存
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSavelnstanceState(outState);
String tempData = "Something you just typed";
outState.putString("datakey", tempData);
}
数据恢复:
修改MainActivity的onCreate ()方法
@Override
protected void onCreate(Bundle savedlnstanceState) {
super.onCreate(savedlnstanceState);
Log.d(TAG, "onCreate"); setContentView(R.layout.activitymain);
if (savedlnstanceState != null) {
String tempData = savedlnstanceState.getString("data^key");
Log. d(TAG, tempData);
}
}
二、活动的启动模式
启动模式一共有4种,分别是standard.、singleTop.、singleTask和 singlelnstance,可以在 AndroidManifest.xml 中通过给<activity>标签指定 android: launchMode 属性来选择启动模式。
standard
standard是活动默认的启动模式,在不进行显式指定的情况下,所有活动都会自动使用这种启动模式。每当启动一个新的活动,它就会在返回栈中入栈,并处于栈顶的位置。对于使用standard模式的活动, 系统不会在乎这个活动是否已经在返回栈中存在,每次启动都会创建该活动的一个新的实例。
@Override
protected void onCreate(Bundle savedlnstanceState) {
super.onCreate(savedlnstanceState);
Log.d("FirstActivity", this.toString());
setContentView(R.layout.firstlayout);
Button buttonl = (Button) findViewByld(R.id.buttonl);
buttonl.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent(FirstActivity.this, FirstActivity.class);
startActivity(intent);
}
});
}
在活动中调用活动本身,会发现调用了几次,返回也要几次。
singleTop
当活动的启动模式指定为 singleTop,在启动活动时如果发现返回栈的栈顶已经是该活动,则认为可以直接使用它,不会再创建新的活动实例。
<activity
android:name=".FirstActivity"
android :launchMode="singleTop"
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
如果该活动并没有处于栈顶的位置,还是可能会创建多个活动实例的
singleTask
每次启动该活动时系统首先会在返回栈中检查是否 存在该活动的实例,如果发现已经存在则直接使用该实例,并把在这个活动之上的所有活动统统出栈,如果没有发现就会创建一个新的活动实例。
<activity
android:name=".FirstActivity"
android: LaunchMode=llsingleTaskl>
android:label="This is FirstActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
活动的最佳实践
知晓当前是在哪一个活动
新建一个BaseActivity类(java类)
public class BaseActivity extends AppCompatActivity {
©Override
protected void onCreate(Bundle savedlnstanceState) {
super.onCreate(savedlnstanceState);
Log.d("BaseActivity", getClass().getSimpleName());
}
}
然后让其他类继承该类,现在每当我们进入到一个活动的界面,该活动的类名就会被打印出来,这样我们就可以时时 刻刻知晓当前界面对应的是哪一个活动了。
随时随地退出程序
新建一个Activitycollector类作为活动管理器
public class Activitycollector {
public static List<Activity> activities = new ArrayList<>();
public static void addActivity(Activity activity) {
activities.add(activity);
}
public static void removeActivity(Activity activity) {
activities.remove(activity);
}
public static void finishAH() {
for (Activity activity : activities) {
if (!activity.isFinishing()) {
activity.finish();
}
}
}
}
接下来修改BaseActivity中的代码,如下所示:
public class BaseActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedlnstanceState) {
super.onCreate(savedlnstanceState);
Log.d("BaseActivity", getClassO.getSimpleName());
ActivityCollector.addActivity(this):
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityCollector.removeActivity(this);
}
}
从此以后,不管你想在什么地方退出程序,只需要调用ActivityCollector. finishAll () 方法就可以了。
当然你还可以在销毁所有活动的代码后面再加上杀掉当前进程的代码,以保证程序完全退 出,杀掉进程的代码如下所示:
android.os.Process.killProcess(android.os.Process.myPid());
其中,killProcessO方法用于杀掉一个进程,它接收一个进程id参数,我们可以通过 myPid()方法来获得当前程序的进程ido需要注意的是,killProcessO方法只能用于杀掉当前 程序的进程,我们不能使用这个方法去杀掉其他程序。
启动活动的最佳写法
即将所有Intent封装到一个方法里面。
public class SecondActivity extends BaseActivity {
public static void actionstart(Context context, String datal, String data2) {
Intent intent = new Intent(context, SecondActivity.class);
intent.putExtra("paraml", datal);
intent.putExtra("param2", data2);
context.startActivity(intent);
}
}
这样传送的数据就能一目了然