Activity基础

很多的内容都是来自于”Android开发艺术探究”这本书,希望写完这篇笔记。可以全方面的了解Activity。

一,Activity的生命周期

这里Activity分为两种情况考虑:
①典型情况下的Activity ,用户正常操作的情况。
②异常情况下的Activity ,Activity被系统回收,或者由于一些缘故被销毁重建。

1,典型情况下的Activity的生命周期

进入A活动:

 A: onCreate
 A: onStart
 A: onResume

从A活动跳到到B活动:

 A: onPause
 B: onCreate
 B: onStart
 B: onResume
 A: onStop

从B返回A:

B: onPause
A: onRestart
A: onStart
A: onResume
B: onStop
B: onDestroy

onCreate,Activity第一个执行的方法,表示创建Activity。setContentView加载布局资源都在这里进行。

onRestart,Activity被重新启动。比如上面的B回退到A,A从不可见到可见时会调用。

onStart,Activity获得了焦点,获得焦点的意思是用户可以看见,但是无法和用户交互,比如无法响应用户的点击等。

onResume,Activity变得可见。

onPause,失去焦点。
比如在A活动中弹出一个透明主题的Dialog或Activity,A活动会失去焦点,会执行onPause。但不会执行onStop。

onStop,用户不可见。
锁屏和回到桌面,Activity会不可见,会触发onStop执行。
onPause和onStop不可以执行耗时的操作,因为会影响新的Activity的启动。

onDestroy,Activity被销毁。
onCreate和onDestroy只可以被执行一次。

2,异常情况下Activity的生命周期
①横竖屏切换时导致的Activity销毁重建
②资源不足导致的优先级低的Activity被杀死

2.1横竖屏切换时导致的Activity销毁重建

进入A活动:

 A: onCreate
 A: onStart
 A: onResume

A活动横竖屏切换

A: onPause
A: onSaveInstanceState
A: onStop
A: onDestroy 

A: onCreate A: onStart A: onRestoreInstanceState A: onResume

A活动销毁被重建。这种情况属于Activity在异常情况下被终止,系统会调用onSaveInstanceState方法用来保存当前Activity的状态数据,当该Activity重新被创建时,则会调用onRestoreInstanceState,把保存当前Activity的状态通过Bundle传递过来。
onSaveInstanceState和onRestoreInstanceState被调用只会出现在Activity异常终止时会调用,正常情况不会被调用。

可以利用Bundle把销毁前的CheckBox的状态记录下来。

 @Override
    protected void onSaveInstanceState(Bundle outState) {
        outState.putBoolean("box",box.isChecked());
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onRestoreInstanceState(Bundle savedInstanceState) {
        box.setChecked(savedInstanceState.getBoolean("box"));
        super.onRestoreInstanceState(savedInstanceState);
    }

避免横竖屏导致的Activity重建,有两种方法:
第一种,让Activity的屏幕方向锁定。

android:screenOrientation="portrait"    竖直方向
android:screenOrientation="landscape"   水平方向

第二种,为Activity指定configChanges属性。

android:configChanges="orientation"

2.2资源不足导致的优先级低的Activity被杀死

Activity的优先级:
        最高的:就是和用户正在交互的Activity
        其次:比如弹出一个对话框或透明的Activity,失去焦点的Activity
        最后:回到桌面或锁屏的Activity,此时已经不可见系统内存不足时,
             就会按照上面的优先级去杀死该Activity所在的进程。
             而如果一个Activity没有四大组件,将会被很快杀死。       

二,Activity的启动模式

为什么会有多种Activity的启动模式?
每跳到一个Activity,系统就会创建它的实例把该Activity放入堆栈。按回退键,Activity会出栈。而如果误操作多次的开启同一个Activity,按照这种堆栈结构,要不断的回退才能恢复到最初。默认的启动模式很呆板,所以就有了多种启动模式。

(1)standard
默认的标准模式,每次启动Activity都会创建其实例。

A,B均是standard模式下
A--->B    B活动会进入到A活动所在的栈中。
B--->B    会重新创建B的实例,进入到堆栈中
此时的堆栈情况是ABB。    

(2)singleTop
栈顶复用模式,当新的Activity位于栈前,那么该Activity不会被重新创建。

B为singleTop模式下
如果目前的栈内是AB,此时要跳到B
AB--->B,此时的栈内依然是AB。而B活动的onNewIntent方法会被回调。  

(3)singleTask
栈内复用模式,这种模式下的Activity,只要在栈内存在,多次启动此Activity也不会创建实例。

D为singleTask模式
假如此时的栈内有ABC三个活动,栈的名字为task1。
ABC--->D   如果D活动所需的栈是task2,首先会先创建task2的任务栈,把D的实例压入task2中。
           而D活动所需栈是task1,那么把D压入到task1的任务栈,此时栈内就是ABCD。       

B为singleTask模式
假如此时的栈内有ABC三个活动,栈的名字为task1。
ABC--->B  如果B活动所需的栈是task2,首先会先创建task2的任务栈,把B的实例压入task2中。    
          如果B活动所需栈是task1,由于task1栈内已经有了B实例,所以不会创建其实例。
          而singleTask的模式默认具有clearTop的效果,会把栈内B以上的Activity移出栈,此时的栈内是AB。   

(4)singleInstance
单实例模式,具备此模式的Activity只能单独的存在于一个栈内。

A活动跳到singleTask模式的B,可以打印每个Activity的getTaskId()的值,会发现无论怎么样,没有一个Activity的taskId和B是一样的。

三,IntentFilter的匹配
众所周知,Activity的启动,可以是显示调用也可以是隐式调用。
显示调用指明需要启动的Activity的在那个包,类名是什么。而隐式调用则需要intent可以匹配Intent-Filter中所设置的过滤信息,匹配才可以被调用起来。

Intent-Filter中的例子:

<intent-filter>
    <action android:name="myaction"/>
    <category android:name="mycagetory"/>
    <category android:name="android.intent.category.DEFAULT"/>
    <data android:mimeType="mimeType"/>
</intent-filter>

action:
系统有自己定义的action,同样我们也可以自己定义。
在调用activity时,intent的action必须存在且和过滤规则中的任意一个action相同就可以匹配上。
如果过滤规则中没有指定action,那么在intent中指定action会报错。
同样在过滤规则中指定了action,但intent中不指定,也会出现问题。

category:
系统也同样有自己的category,我们也可以自定义。
同样的,只要intent中有category和过滤规则中的category有一个相同,就能匹配上。不过有一个特别重要的一点:

在startActivity和startActivityForResult都会为intent添加上一个默认的category:android.intent.category.DEFAULT。
所以在过滤规则中必须要加上
<category android:name="android.intent.category.DEFAULT"/>
否则怎么也匹配不上。因为过滤规则中没有,而你添加了,那么怎么也都不能把activity调起来。

data:

<data
     android:scheme=""
     android:host=""
     android:port=""
     android:path=""
     android:pathPattern=""
     android:pathPrefix=""
     android:mimeType="mimeType"
     />

data总共由两部分组成,一个是mime类型和URI。
mime类型指媒体格式,比如image/jpeg,audio/mpeg4-generic和video/*,可以表示图片,视频等不同的媒体格式。
URI的格式:
http://192.168.1.100:8080/flight/index.hmtl

其中scheme表示URI的模式,比如上面是http,还可以是content,flie等。如果没有指定scheme,那么整个URI是无效的。

host表示URI的主机名
port表示URI的端口
path,pathPattern,pathPrefix表示路径信息,path表示完整的路径信息,而pathPattern也可以表示完整的路径信息,但可以使用通配符“*”来表示任意的字符。由于正则表达式的规范

“*”要写为“\\*”
"\"要写为"\\\\"

而pathPrefix表示的是路径的前缀。

<intent-filter>
  .......... 
  ..........            
    <data
         android:mimeType="image/*"
         />
 </intent-filter>

要怎么匹配上面的过滤规则?
上面的过滤规则并没有指定URI的值,但是URI是有默认值的,默认值为content和file。
所以要写为:

intent.setDataAndType(Uri.parse("file://xxx"),"image/png");
或者
intent.setDataAndType(Uri.parse("content://xxx"),"image/png");

但不可以这样写:

intent.setData("file://xxx");
intent.setType("image/png");
原因是setData中会将mineType置为null。而同样setType中会将URI置为null。

判断隐式意图开启activity是否成功,可以使用PackageManager的resolveActivity方法

public abstract ResolveInfo resolveActivity(Intent intent, int flags);

当返回的是null,表示启动失败。其中传入的flags要使用MATCH_DEFAULT_ONLY。它表示仅仅匹配那些在intent-fliter中声明了默认的category的Activity。
因为activity不声明默认的category,这个activity是无法被隐式意图调用起来的。

你可能感兴趣的:(android)