标签:android activity 生命周期 启动模式 数据传递通信
Activity 是我们在学习android 的时候最先接触到的东西,也是android 开发过程中不可少的组件。而 在我们android 学习中,对activity 有个全面的认识是很重要的。本人在学习android 以来,对activity 也是又爱又恨,所以特意做了个总结,希望能对 那些 activity 认识还不够的“同鞋”一些帮助。
内容提要
1、Activity 的概念
2、Activity 类继承关系
3、Activity 的生命周期
4、Activity 横竖屏切换时生命周期变化
5、Activity 启动模式
6、Activity 之间通信数据传递
7、Activity 的回收与数据保存
内容详情
1、Activity 的概念
在谷歌给的官方Android Api文档中,是这么描述 Activity中的:
一个 activity 是一个单一的,聚焦了用户可以做的事情。几乎所有的 activity 都与用户进行交互,因此 activity 需要关注创建一个窗口,可以通过 setContentView(int) 来更新替换 UI 视图界面。activity 往往是以全屏方式呈现给用户的,你也可以通过设置主题或将activity嵌入其他activity 的方式来改变。
2、Activity 类继承关系
通过这张类图,我们可以看到,activity 是继承于 ContenttextThemeWrapper 类的,是它的直接也是唯一子类。
而activity 的直接子类 则有ActivityGroup、AliasActiviyt、ExpandableListActivity和 ListActivity,其中常用的有 ListActivity (后面再讲List 相关用法时,会讲下ListActivity的相关用法)。
3、Activity 的生命周期
相信这张图你已经见过很多次了吧,经典永远是值得学习的。下面我们就来好好学习下经典。
所有的 activity 都会实现两个方法:onCreate() 和 onPause()方法。
下面就来具体讲讲图中的各个方法详情和都在什么情况下调用:
onCreate: 在这里创建界面,做一些数据的初始化工作
onStart: 到这一步变成用户可见不可交互的
onResume: 变成和用户可交互的,(在activity 栈系统通过栈的方式管理这些个Activity的最上面,运行完弹出栈,则回到上一个Activity)
onPause: 到这一步是可见但不可交互的,系统会停止动画等消耗CPU 的事情从上文的描述已经知道,应该在这里保存你的一些数据,因为这个时候你的程序的优先级降低,有可能被系统收回。在这里保存的数据,应该在onResume里读出来,注意:这个方法里做的事情时间要短,因为下一个activity不会等到这个方法完成才启动
onstop: 变得不可见,被下一个activity覆盖了
onDestroy: 这是activity被干掉前最后一个被调用方法了,可能是外面类调用finish方 法或者是系统为了节省空间将它暂时性的干掉,可以用isFinishing()来判断它,如果你有一个ProgressDialog在线程中转动,请在onDestroy里把他cancel掉,不然等线程结束的时候,调用Dialog的cancel方法会抛异常的。
注:onPause,onstop, onDestroy,三种状态下 activity都有可能被系统干掉。
正常启动activity:onCreate-> onStart -> onResume(启动)
正常退出activity: (启动)-> onPause-> onStop -> onDestroy(退出)
activity 启动后被打断,进入一个新全屏activity:
(启动)-> onPause->onStop
恢复时:onStart->onResume
activity 启动后被打断,进入一个不是全屏的窗口,如Dialog之类的:
(启动)-> onPause
恢复时:onResume
4、Activity 横竖屏切换时生命周期变化
在android 程序清单中声明activity 时我们可以设置 activity在横竖屏切换时的生命周期变化,具体情况如下:
不设置Activity的android:configChanges时,切屏会重新调用各个生命周期,切横屏时会执行一次,切竖屏时会执行两次。
设置Activity的android:configChanges="orientation"时,切横,竖屏时生命周期只会执行一次。
设置Activity的android:configChanges="orientation|keyboardHidden"时,切屏不会重新调用声明周期,只会执行onConfigurationChanged方法。
5、Activity 启动模式
我们知道在继承一个activity类时,当我们要将自己写的 activity启动的时候,我们需要在 androidManifest.xml 程序清单里面,声明所要启动的 activity,而在声明 activity 的同时 我们可以设置activity 的启动模式,launchModel = "...",在android 系统中 ,activity 有四种启动模式,而系统默认是 standard,启动模式在某些需求的情况下可以方便系统 对activity 的管理。
下面说解讲下四种启动模式的各自的特点和区别:
standard:
默认模式,可以不用写配置。
activity在同一个任务栈,
每启动一个activity,都会默认创建一个新的实例。
因此,在这种模式下,可以有多个相同的实例,也允许多个相同Activity叠加。
singleTop:
activity在同一个任务栈,
当要启动的activity处于栈顶时,重复启动之前已创建的实例;
当要启动的activity 不处于栈顶时,会创建新的实例
singleTask:
activity在同一个任务栈,只在一个实例,若创建了将不重复创建;
在启动已在栈里面有的activity时(由栈顶的activity(B) 跳转到下面的 activity (A)时),会将在A上面的activity 一直弹出,一直到A。
singleInstance:
每个activity是独立任务栈,且只放一个activity实例, activity的之间的切换会在几个不同任务栈之间跳转。
6、Activity 之间通信数据传递
在平常的android 开发过程中, 很多活动界面之前是需要传递数据的,也就是说在activity之间是需要传递数据,而数据怎么传递,传递什么样的数据,这些都要有一定的了解。
下面详细介绍:
1、简单数据采用 Intent 来传递
A->B
A中 绑定数据:
Intent intent = new Intent( this, MyReceiver.class);
intent.putExtra( "data", "data from A");
StartActivity(intent);
B中 接收数据:
String data = intent.getStringExtra( "data");
2、数据包采用Bunde 来传递
A->B
A中 绑定数据:
Bundle b = new Bundle();
b.putString("string","String data from A");
b.putInt("int","Int data from A");
b.putBoolean("boolean","Boolean data from A");
Intent intent = new Intent( this, MyReceiver.class);
intent.putExtra("datas",b);//intent.putExtra(b);
B中接收数据:
Bundle b = getIntent.getExtras("datas")//b = getIntent().getExtras();
String datastr = b.getString("string","default");//default为缺省值
3、对象的传递
A->B ,class User (name,age)
1》Serializable java语言提供 ,效率较低
User中:继承Serializable , class User implements Serializable
A中: intent.putExtra("user",new User());
B中: User user = (User)getIntent().getSerializableExtra("user");
2》Parcelable 专门面向移动端,效率较高
User中:继承Parcelabe , class User implements Parcelable
实现两方法:
public int describeContents(){return 0}
public void writeToParcel(Parcel dest, int flags){
dest.writeBundle()//这样可以传递很多相同类型数据了
dest.writeString(getName());
dest.writeInt(getAge());
}
public static final Creator<User> CREATOR = new Creator<User>(){
public User createFromParcel(Parcel source){
source.readBundle();//
return new User(source.readString(),source.readInt());
}
public User[] newArray(int size){
return new User[size ];
}
}
A中: intent.putExtra("user",new User());
B中: User user = (User)getIntent().getParcelableExtra("user");
3、从被启动的activity 传递数据到 主activity(返回传递数据)
A->B,B->A
B中:返回时监听:
String bData;
Intent intent = new Intent();
intent.putExtra("dataB",bData );
setResult(1,intent);//返回状态码可以自行设定
finish();
A中:在启动时:
startActivityForResult(intent, 0);//返回的请求码
实现方法:onActivityResult(int requestCode,int resultCode,Intent data)
onActivityResult(int requestCode,int resultCode,Intent data){
if(requestCode == 0){
if(resultCode == 1)
String s = data.getStrignExtra("dataB");
}
}
4、还有一种懒汉方法来传递数据,进行通信如设置一个公共类,在公共类中,将要传递的数据声明为 公有静态的(public static ),这样就可以在直接在activity之间进行通信了。当然这种数据也可以放在 application 这个全局的 类里面。这种方法通常是用来判断 是否登陆超时,或是一些全局的配置等等。
7、Activity 的回收与数据保存
之前在讲解 activity 生命周期的时候,我们就已经知道了,activity 在某些情况下会被系统干掉的,如果这个activity 又在做一些重要的数据,举一个简单的例子, 我们在登录一个时,只填写了一部分,临时离开了这个界面,当我们返回时,如果又需要重新在填写全部的数据,这是不是有点坑,,,严重影响用户体验。
当然这只是举的一个小例子,或许有点不恰当,但我们确实是需要在系统回收 activity ,activity被异常干掉的时候保存当前的用户数据 ,而在再次打开或恢复时,应当能还原当初的数据。
因为 activity 的切换,所以当用户在再次切换回原来的 activity的时候,原先的 activity 有两种情况:一种是被回收,一种是没有被回收,
被回收的A就要重新调用onCreate()方法,不同于直接启动的是这回onCreate()里是带上参数
savedInstanceState,没被收回的就还是onResume就好了。
savedInstanceState是一个Bundle对象,你基本上可以把他理解为系统帮你维护的一个Map对象。在onCreate()里你可能会用到它,如果正常启动onCreate就不会有它,所以用的时候要判断一下是否为空。
前面在生命周期也讲过,我们可以在onPause 方法中 保存数据,而在 onResume 方法中恢复数据。
其实谷歌早就考虑到了关于 activity 异常退出,被系统回收的 的 数据 保存与恢复相关的问题。
那就是这两个方法: onSaveInstanceState(Bundle outState) 和 onRestoreInstanceState(Bundle savedInstanceState) 方法,这两个 前者是负责在activity被异常干掉之前保存数据,而后者是负责恢复数据。
注:
onSaveInstanceState()方法,在正常情况下就不会被调用的,只有当 activity 发生异常时才会被调用。
onRestoreInstanceState()方法,系统会调用,其实也是不需要我们人为去干涉的。
我们接着看,注意 onSaveInstanceState(Bundle outState )方法的参数,是的,是 Bundle 类型的,还记得前面提到过的 数据传递部分吗,Bundld 就可以保存大多数的数据。 现在或许有人说 onRestoreInstanceState() 方法我们可以不去多管,总感觉心里不踏实,是吧,那我们在哪个地方 将 outState 里面保存的数据拿出来呢?
我们再看看 onCreate(Bundle savedInstanceState) ,是不是发现什么了,这个参数,也是Bundle 类型的,其实这里的 savedInstanceState 就是之前保存的 outState,而我们可以在onCreate 方法中取消之前 保存的数据。
最后问的归纳如下:
保存数据:
void onSaveInstanceState(Bundle outState) { super.onSaveInstanceState(outState); outState.putLong("id",1234567890); }
判断 和 恢复 数据:
void onCreate(Bundle savedInstanceState){ .......... if(savedInstanceState != null){ ..... } }
好了,到这里我们对 activity 已经有了个大概的理解了,而博客也到这里结束了。这是 本人 第一次写的 关于 android 的文章 ,从自己学习android 以来,中间有苦有甜,有笑有泪,不容易啊,今天在我即将走出校园,即将用 android 来谋生的同时,写下这篇博客,希望能在android这条路上走得越来越宽,越来越远。
注:这博客是总结型的,中间有我自己对 android api 的翻译,同样其中不免有些知识点是有和其他文章有相通的,所以如果有失礼或者是有不是很恰当的地方,还请前辈们见谅。
本文出自 “开云” 博客,请务必保留此出处http://kaiyun.blog.51cto.com/8015683/1758519
标签:android activity 生命周期 启动模式 数据传递通信
原文地址:http://kaiyun.blog.51cto.com/8015683/1758519