2.5Activity活动

活动有四种启动模式,standard模式是默认模式,如需改为其他,在AndroidManifest.xml中<activity>标签中指定android:launchMode="××××××××"

2.5.1 standard

该模式为默认模式,当你进入一个活动,上一个活动就被压在下面,新活动出现在栈顶,再出现新的,就一层一层从上往下压,如果点击返回,最上面就会消失,第二层就会上来,如果你要退出整个应用,就要将返回栈中的活动全取消掉,更加极端一点,你不停的进入同一个活动100次,就要返回100次,,因为在返回栈中有100个相同的十里,尽管是相同的。

2.5.2 singleTop

在这个模式中,他会检查你是不是在栈顶,如果不是就会启动,如果是就会直接使用,只需点击一次就会退出

2.5.3 silgleTask

这种相对智能一点,他会检查返回栈内有没有你想启动的活动,有的话直接拿到栈顶,没有的话,再启动。

2.5.4 singleInstance

这种比较特殊,是为了与别的应用共享同一个活动,如果你的应用想要别的应用调用你的某一个界面,这种模式会让你I想跟别的应用共享的界面单独造出一个单独使用的返回栈,不会跟别的返回栈共同使用。

Intent中标志位设置启动设备

在上文中的四种模式都是在mainfest的xml文件中进行配置的,GoogleAndroid团队同时提供另种级别更高的设置方式,即通过Intent.setFlags(int flags)设置启动模式;

FLAG_ACTIVITY_CLEAR_TOP : 等同于mainfest中配置的singleTask,没啥好讲的;
FLAG_ACTIVITY_SINGLE_TOP: 同样等同于mainfest中配置的singleTop;
FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS: 其对应在AndroidManifest中的属性为android:excludeFromRecents=“true”,当用户按了“最近任务列表”时候,该Task不会出现在最近任务列表中,可达到隐藏应用的目的。
FLAG_ACTIVITY_NO_HISTORY: 对应在AndroidManifest中的属性为:android:noHistory=“true”,这个FLAG启动的Activity,一旦退出,它不会存在于栈中。
FLAG_ACTIVITY_NEW_TASK: 这个属性需要在被start的目标Activity在AndroidManifest.xml文件配置taskAffinity的值【必须和startActivity发其者Activity的包名不一样,如果是跳转另一个App的话可以taskAffinity可以省略】,则会在新标记的Affinity所存在的taskAffinity中压入这个Activity。

startActivity场景

Activity的启动模式的应用的设置是和它的开发场景有关系的,在App中打开新的Activity的基本上分为两种情况:

目标Activity是本应用中的Activity,即它的启动模式是可以直接在fanifest中配置或者默认为standard,任务栈也可以自己随意设置;
目标Activity是第三方App中的Activity,这个时候就需要先考虑打开新Activity的是和自己App放在同一任务栈中还是新的task中【这个是很重要的因为在Android的机制中:同一个任务栈中的activity的生命周期是和这个task相关联的[具体实例见下文]】,然后考虑Activity的启动模式; 所以Android提供了优先级更高的设置方式在Intent.setFlags(int flags),通过这setFlags就可以为打开第三方的App中Activity设置任务栈和启动模式了,具体设置就自己去看源码了。

四种启动方式常用场景

 

2.6活动的最佳实践

2.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());
    }
}

我们要让BaseActivity成为整个应用中所有活动的父类,修改继承关系,改为继承BaseActivity,由于BaseActivity继承自AppCompatActivity,所以不会影响功能

public class MainActivity extends BaseActivity {
public class NormalActivity extends BaseActivity {
public class DialogActivity extends BaseActivity {

重新运行:
 

07-19 15:37:38.048 5375-5375/? D/BaseActivity: MainActivity
07-19 15:37:41.845 5375-5375/? D/BaseActivity: NormalActivity
07-19 15:37:46.014 5375-5375/? D/BaseActivity: DialogActivity
07-19 15:37:48.229 5375-5375/? D/BaseActivity: NormalActivity
07-19 15:37:50.436 5375-5375/? D/BaseActivity: DialogActivity

得到这样的效果,完美不

2.6.2随时随地退出程序

如果想退出程序,但是返回栈内堆积了很多的活动,要点击跟多次Back键才行,Home键也只能把程序挂起,并不能退出程序,所以建立一个专门的集合类来管理活动,新建一个ActivityManager.xml类作为活动管理类:

public class ActivityManager {
    public static List<Activity> activitys = new ArrayList<>();
    public static void addActivity(Activity activity){
        activitys.add(activity);
    }
    public static void remroveActivity(Activity activity){
        activitys.remove(activity);
    }
    public static void finIshAll(){
        for (Activity activity :activitys){
            if ( !activity.isFinishing()){
                activity.finish();
            }
        }
    }
}

我们创建一个list暂时存放活动,提供addActivity()来将活动添加到list中,remoriveActivity()用于从list中一处活动,finishAll()用于将所有活动销毁。

我们在BaseActivity中修改为:

public class BaseActivity  extends AppCompatActivity{
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Log.d("BaseActivity",getClass().getSimpleName());
        ActivityManager.addActivity(this);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        ActivityManager.remroveActivity(this);
    }
}

在onCreate()中调用活动管理类ActivityManager()中addActivity()将创建的活动添加到list中,然后重写onDestory()方法,调用活动管理类的remroveActivity()来表明有一个马上要销毁的活动从活动管理器中销毁。

不管在任何界面,只要调用activityManager().finishAll();就尅呀不直接退出程序:

noraml_textview.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                ActivityManager.finIshAll();
            }
        });

PS:杀死所有活动后面还可以加上杀死当前活动的代码,以保证完全退出:

android.os.Process.killProcess(android.os.Process.myPid());

其中killProcess()只能杀死一个进程,myPid()获取当前进程的id,谨记,该方法只能用于杀死当前进程,不能杀死其他进程。

2.6.3启动活动的最佳写法

当你需要启动一个活动并且需要传递数据的时候,被传递数据的活动情况并不清楚,有更好的办法解决:

在NormalActivity活动添加以下代码:

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

将数据通过actionStart()的参数传递过来,然后保存在Intent中,然后调用startActivity()启动NormalActivity,清楚明白的看出传递了什么数据,简化了启动活动的代码:

NormalActivity.actionStart(MainActivity.this,"12138","立正");

在NormalActivity中取出数据:

        Intent intent3 = getIntent();
        String data1 = intent3.getStringExtra("param1");
        String data2 = intent3.getStringExtra("param2");
        noraml_textview.setText(data1 + data2);

将编写的每个活动都添加类似的方法,可以将启动活动变得很简单。

Activity异常生命周期与应用

这里的系统配置改变是指由于横竖屏切换等引起的Activity生命周期的变化,进而引发的资源的变化。在Android中系统配置改变是会引起Activity销毁重建的,例如横竖屏切换,只是切换时间差太小,用户眼睛不能察觉而已。activity重建的时候就在之前Activity销毁前,系统会先调用onSaveInstanceState(Bundle outState)存储当时各种状态,在新建Activity中Android会通过onRestoreInstanceState(Bundle savedInstanceState)读取数据并自动恢复到之前Activity的View,当然在Activity中开发者自己的代码逻辑就需要自己处理啦。

触发onSaveInstanceState(Bundle outState)的条件:
1、当用户按下HOME键时。
2、从最近应用中选择运行其他的程序时。
3、按下电源按键(关闭屏幕显示)时。
4、从当前activity启动一个新的activity时。
5、屏幕方向切换时(无论竖屏切横屏还是横屏切竖屏都会调用)。
在前4种情况下,当前activity的生命周期为:
onPause -> onSaveInstanceState -> onStop。

系统回收引起异常:

在Android系统内存不足时,同时Activity失去焦点后被系统给回收后,Activity 再次被创建时,通过onSaveInstanceState 和onRestoreInstanceState来存储恢复数据再次显示在屏幕上之前的View等状态;

Activity异常基础处理

1.最常见的是在onCreate(Bundle savedInstanceState)中通判断savedInstanceState是否为空,恢复Activity中的数据体;
2.另一种就是根据应用场景在mainfest中配置各种参数尽可能减少由于配置参数引起的Activity异常;
3.使用onConfigurationChanged方法代替onRestoreInstanceState实现恢复数据逻辑,更高级的自然就是性能优化、实时监视的思路啦;

onSaveInstanceState和onRestoreInstanceState

如果系统由于系统约束(而不是正常的应用程序行为)而破坏了Activity,那么尽管实际 Activity实例已经消失,但是系统还是会记住它已经存在,这样如果用户导航回到它,系统会创建一个新的实例的Activity使用一组保存的数据来描述Activity在被销毁时的状态。系统用于恢复以前状态的已保存数据称为“实例状态”,是存储在Bundle对象中的键值对的集合。

这样这两个方法就有用武之地了,特别要注意的是:

1、如果是用户自动按下返回键,或程序调用finish()退出程序,是不会触发onSaveInstanceState()和onRestoreInstanceState()的。
2、每次用户旋转屏幕时,您的Activity将被破坏并重新创建。当屏幕改变方向时,系统会破坏并重新创建前台Activity,因为屏幕配置已更改,您的Activity可能需要加载替代资源(例如布局)。即会执行onSaveInstanceState()和onRestoreInstanceState()的。

Activity添加额外的数据到已保存的实例状态,Activity生命周期中还有一个额外的回调方法,这些回调方法在前面的课程中没有显示。该方法是onSaveInstanceState(),系统在用户离开Activity时调用它。当系统调用此方法时,它将传递Bundle将在您的Activity意外销毁的事件中保存的对象,以便您可以向其中添加其他信息。然后,如果系统在被销毁之后必须重新创建Activity实例,它会将相同的Bundle对象传递给您的Activity的onRestoreInstanceState()方法以及您的onCreate() 方法。

 

当系统开始停止您的Activity时,它会调用onSaveInstanceState()(1),以便您可以指定要保存的其他状态数据,以防Activity必须重新创建实例。如果Activity被破坏并且必须重新创建相同的实例,则系统将(1)中定义的状态数据传递给onCreate()方法(2)和onRestoreInstanceState()方法(3)

当您的Activity开始停止时,系统会调用,onSaveInstanceState()以便您的Activity可以使用一组键值对来保存状态信息。此方法的默认实现保存有关Activity视图层次结构状态的信息,例如EditText小部件中的文本或ListView的滚动位置。

为了保存Activity的附加状态信息,您必须实现onSaveInstanceState()并向对象添加键值对Bundle。例如:

static final String STATE_SCORE = "playerScore";
static final String STATE_LEVEL = "playerLevel";
...

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // 保存用户自定义的状态
    savedInstanceState.putInt(STATE_SCORE, mCurrentScore);
    savedInstanceState.putInt(STATE_LEVEL, mCurrentLevel);
    
    // 调用父类交给系统处理,这样系统能保存视图层次结构状态
    super.onSaveInstanceState(savedInstanceState);
}

恢复您的Activity状态

当您的Activity在之前被破坏后重新创建时,您可以从Bundle系统通过您的Activity中恢复您的保存状态。这两个方法onCreate()和onRestoreInstanceState()回调方法都会收到Bundle包含实例状态信息的相同方法。

因为onCreate()调用该方法是否系统正在创建一个新的Activity实例或重新创建一个以前的实例,所以您必须Bundle在尝试读取之前检查该状态是否为空。如果它为空,那么系统正在创建一个Activity的新实例,而不是恢复之前被销毁的实例。

例如,下面是如何恢复一些状态数据onCreate():

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState); // 记得总是调用父类
   
    // 检查是否正在重新创建一个以前销毁的实例
    if (savedInstanceState != null) {
        // 从已保存状态恢复成员的值
        mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
        mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
    } else {
        // 可能初始化一个新实例的默认值的成员
    }
    ...
}

onCreate()您可以选择执行onRestoreInstanceState(),而不是在系统调用onStart()方法之后恢复状态。系统onRestoreInstanceState()只有在存在保存状态的情况下才会恢复,因此您不需要检查是否Bundle为空:
 

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // 总是调用超类,以便它可以恢复视图层次超级
    super.onRestoreInstanceState(savedInstanceState);
   
    // 从已保存的实例中恢复状态成员
    mCurrentScore = savedInstanceState.getInt(STATE_SCORE);
    mCurrentLevel = savedInstanceState.getInt(STATE_LEVEL);
}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值