Activity异常下的生命周期、启动模式和标记位,隐式启动匹配规则IntentFilter

1,Activity异常情况下的生命周期

在Activity遭遇非正常退出时,其生命周期会有所不同。
例如处于后台的Activity由于内存不足而导致被销毁,由于配置改变而导致的重建等。

  在这种情况下是非用户操作而导致的,也就是说是有可能再次显示的。因此Activity会调用两个方法来进行数据的保存和恢复。onSaveInstanceState(Bundle outState)和onRestoreInstanceState(Bundle savedInstanceState),在异常情况将要销毁Activity时,onSaveInstanceState会被调用,此时可以在该方法中进行数据的存储,可以存储到Bundle中。该方法运行在onStop方法之前。之后重建Activity时会调用onRestoreInstanceState方法进行数据的恢复。
  另外,在onCreate方法中也可以进行数据的恢复,他们的参数中都有Bundle,里面储存着之前保存的数据,不同的是正常情况下onCreate的参数为null,因此要在onCreate中恢复数据时要进行非空检测。

避免配置改变带来的Activity的重建

  当配置改变时,如旋转屏幕等,会造成Activity的重建。即先进行销毁后进行创建,同时进行数据的保存与恢复。
  但有时候不想让Activity重建,那么可以通过配置manifest中Activity的configChanges属性来避免重建。

<activity
   android:name=".MainActivity"
   android:configChanges="orientation">
       <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
       </intent-filte>
</activity>

configChanges 常用的有一下几个:
  locale:地区发生改变,通常是更改系统语言
  orientation:屏幕发生旋转
  keyBoardHidden:键盘状态发生了变化,如调出键盘
  screenSize:屏幕大小发生了变化,旋转屏幕时会改变(api13以上)

若是不想让该Activity重建,则在Activity的配置中加入这几个即可,用‘ | ’ 分隔多个。


  另外的,对于一个Activity(A)启动另一个Activity(B)时,生命周期的顺序为onPause(A)->onCreate(B)->onStart(B)->onResume(B)->onStop(A),因此不能再onPause中进行耗时操作。

2,Activity的启动方式

Activity启动方式有4种,standard,singleTop,singleTask,singleInstance
设置启动模式可以在manifest中的Activity的launchMode中修改

<activity
     android:name=".MainActivity"
     android:launchMode="singleTop"
     android:configChanges="orientation">
        <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
</activity>
standard:标准模式(默认模式)

每次启动Activity时都会创建一个实例放在任务栈上,无论该Activity是否已经被创建。

Intent intent = new Intent(MainActivity.this, MainActivity.class);
startActivity(intent);

log日志:

I/BaseActivity: MainActivity: onCreate
I/BaseActivity: MainActivity: onStart
I/BaseActivity: MainActivity: onResume
I/BaseActivity: MainActivity: onPause
I/BaseActivity: MainActivity: onCreate
I/BaseActivity: MainActivity: onStart
I/BaseActivity: MainActivity: onResume

I/BaseActivity: MainActivity: onStop

singleTop:栈顶复用模式

若是待启动的Activity已经存在于栈顶,则不会重新创建Activity,而是先调用onPause,然后调用onNewInten再调用onResume

log日志:

I/BaseActivity: MainActivity: onCreate
I/BaseActivity: MainActivity: onStart
I/BaseActivity: MainActivity: onResume
I/BaseActivity: MainActivity: onPause
I/BaseActivity: onNewIntent:
I/BaseActivity: MainActivity: onResume

singleTask:栈内复用

  若是待启动的Activity为singleTask模式,并且已经在任务栈中存在。若是处于栈顶,则与singleTop一样,先调用onPause,再调用onNewIntent,最后调用onResume。
  若不是处于栈顶,则它上面的所有Activity都出栈。方法调用顺序:它上面的非栈顶的Activity调用onDestroy,然后原栈顶调用onPause,然后唤醒Activity onNewIntent->onRestart->onStart->onResume,然后原栈顶Activity调用onStop->onDestroy.

I/BaseActivity: ThirdActivity: onDestroy
I/BaseActivity: MainActivity: onPause
I/BaseActivity: TwoActivity: onNewIntent
I/BaseActivity: TwoActivity: onRestart
I/BaseActivity: TwoActivity: onStart
I/BaseActivity: TwoActivity: onResume

I/BaseActivity: MainActivity: onStop
I/BaseActivity: MainActivity: onDestroy

singleInstance:单实例模式

  该模式下的Activity会单独存在一个任务栈,其余与singleTask一样,只是由于该Activity单独存在一个任务栈,因此不会出现singleTask那样的其上Activity全部出栈的情况。
  退出时则按任务栈顺序退出,例如任务栈A调用任务栈B(顺序为A->B),任务栈B调用C(顺序为A->B->C),任务栈C再调用任务栈A(顺序为B->C->A),此时按返回键退出则是先退出A后退出C,最后退出B。

任务栈

Activity默认都是添加到一个与包名相同的任务栈中,也可以通过设置taskAffinity属性来指定任务栈。

<activity
   android:name=".TwoActivity"
   android:launchMode="standard"
   android:taskAffinity="com.example.MyApplication" />
<activity

若是指定了singleInstance模式的taskAffinity,则该Activity会出现在最近访问任务中。taskAffinity只在singleTask和singleInstance中设置有效。

标记位
Intent.FLAG_ACTIVITY_SINGLE_TOP:

  添加该标记位则会在当前栈顶中寻找Activity若是找到,则调用onPause->onNewIntent->onResume。否则创建一个新的Activity。类似于singleTop模式

Intent.FLAG_ACTIVITY_NEW_TASK:

  单独使用没什么作用

Intent.FLAG_ACTIVITY_CLEAR_TOP:

  对于一个standard模式的Activity,加上该标记位则会清除其上的所有Activity(包括自己),然后再重建Activity。
  对于singleTop的Activity,加上该标记相当于singleTask,会清空其上的Activity(不包括自己)并调用onNewIntent->onRestart->onStart->onResume

Activity的Intent启动匹配规则

  启动一个Activity有两种方式,一种是显式启动,一种是隐式启动。
  显示启动是直接通过Activity的类名来启动的。

Intent intent = new Intent(MainActivity.this, MainActivity.class);
startActivity(intent);

  隐式启动是指Activity设置一系列的匹配规则,调用方可以不知道Activity的具体类名,而是通过设置对应的规则来匹配想要的Activity。
  匹配规则分为三个部分,action,category,data。

<activity
    android:name=".MainActivity"
    android:configChanges="orientation"
    android:launchMode="standard">
       <intent-filter>
           <action android:name="android.intent.action.MAIN" />
           <category android:name="android.intent.category.LAUNCHER" />
       </intent-filter>
</activity>

  上面是MainActivity的匹配规则。可以看到匹配规则是在AndroidManifest中的Activity下的intent-filter标签中设置。

action

  对于action,其值是一串任意的字符串,同时也是区分大小写的,并且可以添加多个,只要有一个能够匹配就行。而且要启动一个Activity,action是必须要设置的(在manifest和intent中都要设置)。

<activity android:name=".TwoActivity">
    <intent-filter>
        <action android:name="android.intent.action.TwoActivity" />
        <action android:name="andooid.intent.action.TwoActivity1"/>
        <category android:name="android.intent.category.DEFAULT" />
   </intent-filter>
</activity>
Intent intent  = new Intent();
intent.setAction("android.intent.action.TwoActivity");
startActivity(intent);
category

  category也是一个任意的区分大小写的字符串,但是category与action有些不同,因为在intent中,可以不添加category,而系统会自动添加一个叫做android.intent.category.DEFAULT的category,因此在manifest中,必须添加这个category,不然将会无法启动Activity。
  另外,category也是可以有多个的。但是在intent中添加的所有的category都必须能够匹配,否则将会无法启动Activity。

<activity android:name=".TwoActivity">
       <intent-filter>
              <action android:name="android.intent.action.TwoActivity" />
              <category android:name="android.intent.category.DEFAULT" />
              <category android:name="com.example.MyCategory"/>
       </intent-filter>
</activity>
Intent intent  = new Intent();
intent.setAction("android.intent.action.TwoActivity");
intent.addCategory("com.example.MyCategory");
startActivity(intent);
data

  data由URI和mimeType组成。URI分为schema,host,port,path。在intent-filter中,可以不设置data过滤标签,同时intent中也不能设置。可以只设置URI或者mimeType。
  对于只设置URI而不设置mimeType而言,intent中对应也不能设置mimeType。
  对于只设置mimeType而不设置URI而言,intentmimeType必须设置,URI可以不设置,但若是设置,schema只能是content和file类型,并且不匹配其他host等信息。
  若是同时设置,在intent中也必须同时设置,并且不能分开设置,否则会清除另一个信息。

<activity android:name=".TwoActivity">
   <intent-filter>
       <action android:name="android.intent.action.TwoActivity" />
       <category android:name="android.intent.category.DEFAULT" />
       <category android:name="com.example.MyCategory" />
       <data
          android:host="www.example.com"
          android:mimeType="text/*"
          android:path="/a"
          android:port="80"
          android:scheme="content" />
   </intent-filter>
</activity>
Intent intent = new Intent();
intent.setAction("android.intent.action.TwoActivity");
intent.addCategory("com.example.MyCategory");
intent.setDataAndType(Uri.parse("content://www.example.com:80/a"),"text/*");
startActivity(intent);

//同时设置URI和mimeType的时候要使用setDataAndType()不能使用setData+setType的组合方式。
/*
public @NonNull Intent setData(@Nullable Uri data) {
        mData = data;
        mType = null;
        return this;
}
public @NonNull Intent setType(@Nullable String type) {
        mData = null;
        mType = type;
        return this;
}
*/
//由其方法即可看出在设置其中一项的时候回将另一个设置为null

  对于显示启动的Activity,不会对过滤规则进行匹配,而是直接进行启动。
  另外,对于匹配失败的intent,将会报android.content.ActivityNotFoundException异常。可以使用intent.resolveActivity(getPackageManager())进行判断,当匹配失败的时候,该方法会返回null,可以在返回null的时候取消启动。

if(intent.resolveActivity(getPackageManager())!=null) {
     startActivity(intent);
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值