标签:
Activity是四大组件中最重要的一个组件,以下将从activity生命周期,任务栈及启动模式/设置flag,数据/对象传递及startactivtyforresult的使用,安全退出,Title及基类等几个方面来详述activity的特性。
[转]http://blog.csdn.net/lijianli9/article/details/19072623
一、activity的生命周期:
激活状态 : Activity出于前台 , 栈顶位置;
暂停状态 : 失去了焦点 , 但是用户仍然可以看到 , 比如弹出一个对话框 , 后面的Activity出于暂停状态;
停止状态 : 被其它的Activity覆盖 , 用户不可见 , 但是仍然存在;
onCreate() : 初始化一些成员变量 , 如View等 , 此时进入停止状态;
onStart() : 被用户可见之前调用 , 调用之后进入暂停状态 , 如果不满足条件我们不想让用户进入应用 , 可以在这里进行限制 , finish掉该Activity;
onResume() : 在与用户交互之前调用 , 调用之后进入激活状态;
onPause() : 激活另一个Activity时调用 , 调用之后进入暂停状态 , 界面可见 , 失去焦点; 该操作用来保存当前Activity数据;
onStop() : Activity被覆盖前调用 , 调用之后该Activity不可见; 该方法用来关闭旧的Activity , 注意是完全不可见的时候才会调用这个方法;
onDestroy() : Activity被销毁前调用 ;
注意 : 在暂停状态 和 停止状态 , 如果内存紧张 , 该Activity会被系统回收;也就是除了onResume()和onDestroy(),其他几个方法中都有可能被回收
首先调用onCreate()方法创建Activity进入停止状态 -> 调用onStart()方法进入暂停状态 -> 调用onResume()方法进入激活状态;
A先执行onPause()方法进入暂停状态 -> B执行onCreate()方法进入停止状态 -> B执行onStart()方法进入暂停状态 -> B执行onResume()方法进入激活状态 -> A被完全覆盖执行onStop()方法进入停止状态;
B执行onPause()方法进入暂停状态 -> A调用onRestart()方法进入停止状态 -> A调用onStart()方法进入暂停状态 -> A调用onResume()方法进入激活状态 -> B被覆盖调用onStop()方法进入停止状态 -> B执行onDestroy()方法销毁
这里注意Activity的栈是不可逆的 , 只能后退 , 不能前进 , 回退后 , 原来的栈顶的Activity就马上销毁了.
[转]http://blog.csdn.net/vipzjyno1/article/details/25463457
二.Activity启动模式、任务栈及标志位flag
栈是一种常用的数据结构,栈只允许访问栈顶的元素,栈就像一个杯子,每次都只能取杯子顶上的东西,而对于栈就只能每次访问它的栈顶元素,从而可以达到保护栈顶元素以下的其他元素.”先进后出”或”后进先出”就是栈的一大特点,先进栈的元素总是要等到后进栈的元素出栈以后才能出栈.递归就是利用到了系统栈,暂时保存临时结果,对临时结果进行保护.
栈的定义栈(Stack)是限制仅在表的一端进行插入和删除运算的线性表。(1)通常称插入、删除的这一端为栈顶(Top),另一端称为栈底(Bottom)。 (2)当表中没有元素时称为空栈。(3)栈为后进先出(Last In First Out)的线性表,简称为LIFO表。栈的修改是按后进先出的原则进行。每次删除(退栈)的总是当前栈中"最新"的元素,即最后插入(进栈)的元素,而最先插入的是被放在栈的底部,要到最后才能删除。
Android的管理主要是通过Activity栈来进行,当一个Activity启动时,系统会根据其配置将它压入到一个特定的栈中,系统处于运行状态。
当用户点击返回或则FINISH()了该Activity,那么它便会被从栈中压出,随之摧毁。
按照Activity的生命周期可以知道,如果当前显示的栈中Activity没有被摧毁,那么打开新的Activity时候,会将新打开的压入到栈,原来的根据其显示情况选择状态变化(原Activity依旧可见,变为暂停状态(Paused),如果被完成遮住了,转变为停止状态(Stopped))。
以下举例说明它们的区别:
standard:Activity的默认加载方法,该方法会通过跳转到一个新的activity,同时将该实例压入到栈中(不管该activity是否已经存在在Task栈中,都是采用new操作)。例如: 栈中顺序是A B C D ,此时D通过Intent跳转到A,那么栈中结构就变成 A B C D A ,点击返回按钮的 显示顺序是 D C B A,依次摧毁。
singleTop:singleTop模式下,当前Activity D位于栈顶的时候,如果通过Intent跳转到它本身的Activity (即D),那么不会重新创建一个新的D实例,所以栈中的结构依旧为A B C D,如果跳转到B,那么由于B不处于栈顶,所以会新建一个B实例并压入到栈中,结构就变成了A B C D B。
singleTask:singleTask模式下,Task栈中只能有一个对应Activity的实例。例如:现在栈的结构为:A B C D。此时D通过Intent跳转到B,则栈的结构变成了:A B。其中的C和D被栈弹出销毁了,也就是说位于B之上的实例都被销毁了。
singleInstance:singleInstance模式下,会将打开的Activity压入一个新建的任务栈中。例如:Task栈1中结构为:A B C ,C通过Intent跳转到了D(D的模式为singleInstance),那么则会新建一个Task 栈2,栈1中结构依旧为A B C,栈2中结构为D,此时屏幕中显示D,之后D通过Intent跳转到D,栈2中不会压入新的D,所以2个栈中的情况没发生改变。如果D跳转到了C,那么就会根据C对应的launchMode的在栈1中进行对应的操作,C如果为standard,那么D跳转到C,栈1的结构为A B C C ,此时点击返回按钮,还是在C,栈1的结构变为A B C,而不会回到D。
这一节介绍一下activity之间参数传递。我们知道用intent可以实现activity之间相互跳转,在跳转的同时我们不免也需要传递一些参数,下面就介绍一下如何在一个activity里传递参数,在另一个activity里接受参数。
activity之间有两种参数传递形式:一种是一个activity启动另一个activity的时候传递数据到另一个activity,然后在activity中接受到数据,做相应处理。另一种是一个activity启动另个一activity传递数据,当另个一activity窗口关闭后,在传递数据到启动它的那个activity。
我们先看一下第一种方式
首先先建立一个ActivityDemo项目:
看一下在SecondDemoActivity中怎么接受参数:
点击发送按钮:
OK! 成功。
接下来看看第二种方式:
先看一下页面的布局文件:
看一下运行效果:
这是我通讯录的联系人。点击listview:
返回到了ResultDemoActivity并得到了联系人的名字。
xml序列化传递对象:
四.多个activity的安全退出
在android的用户交互中,按钮触发的意图(Intent)跳转会为你重新打开新的一个界面活动(Activity),对于之前的界面根据需求进行摧毁(Finish())或则保留。
如果一个交互流程中,是从A开始,按照A - B - C - D - A这样的顺序进行的话,那么B,C,D这3个活动界面会根据你D中最后的操作来进行保留或是摧毁,例如
(1)注册流程中,在A界面点击注册,通过B,C,D界面完成注册后,B,C,D就随之摧毁,而如果D中注册不成功没跳转会A的话,那么B,C,D就不能摧毁,之前所填的内容也必须保留。
(2)客户端交互中,返回首页按钮,由于在频繁的点击打开过多的界面(如微信查看朋友圈),返回首页就必须一个一个back回去,所有有的客户端为了优化用户体验,便会加入一个按钮返回首页(之前打开的全部关闭)。
以上几个例子都涉及到了 --- 如何安全退出多个ACTIVITY 这个问题。
其实,这个问题的解决方案有好多种,并且各有各的优缺点,下面就罗列出多个方案以及各个方案的优缺点所在,以便用户根据需求选择。
首先,通过大致的思维导图罗列出了以下几个知识点,来帮助你去分析学习:
3.Application : 全局的使用
4.Activity: onActivityResult(int requestCode, int resultCode, Intent data)方法
5.栈的概念:Last-In/First-Out(LIFO) --- 后进先出的原则
6.BroadcastReceiver 广播
7.栈的引申的知识点:(1)ArrayList和LinkedList的区别 (2)android 栈和队列
以上的 (1)Activity的启动模式 (2)intent: Flags属性 (3)栈的概念
我通过一篇文章写明了他们3者的联系可以点击以下链接查看
Activity启动模式 及 Intent Flags 与 栈 的关联分析
思路:通过Intent的Flags来控制堆栈去解决
android中,每打开一个Activity,便会在栈中加入一个Activity,当该Activity被摧毁后,栈中便移除了它,并且栈中的Activity是按照开打的先后顺序依次排排列的。
Android的窗口类提供了历史栈,我们可以通过stack的原理来巧妙的实现,这里我们在A窗口打开B窗口时在Intent中直接加入标 志 Intent.FLAG_ACTIVITY_CLEAR_TOP,这样开启B时将会清除该进程空间的所有Activity。
代码:
在注册流程最后的FourthStep.class中,点击完成注册点击事件
其中的 INTENT_METHOD_FIRST_SINGUP 是登录界面的Intent隐式Action。
优缺点:
优:使用对栈的巧妙利用,不会赞成内存无故占用等问题,个人认为这个方法是首选。
思路:通过堆栈管理器,对Stack进的存储Activity进行操作(推入,推出,弹出)
代码:
之后在注册流程中的对应步骤的Activity的onCreate()中把当前Activity推入栈列表,完成注册流程后,弹出栈列表中流程所涉及的Activity。
优缺点:
缺:如果处理不当,容易造成不在当前界面的Activity被全局引用而摧毁不掉,内存得不到释放,从而无故占用不必要的内存。
思路:通过在Application中用一个列表来记录当前所打开的Activity,根据需求去遍历finish()。
描述:和方案2有点类似。
代码:
使用流程和方法2类似。
优缺点:
缺:如果处理不当,容易造成不在当前界面的Activity被全局引用而摧毁不掉,内存得不到释放,从而无故占用不必要的内存。
方法:使用广播机制解决
思路:通过Activity创建的时候,设置监听广播,在注册流程最后步完成注册时候,发送广播进行遍历finish().
描述:这里我把这些广播的初始化都写在了基类BaseActivity里面,便于维护。
代码:
在流程中的每步Activity中,初始化广播,之后在点击完成注册时候,发送广播
优缺点:
缺:开启过多的广播监听,觉得会浪费资源。
方法:通过Activity跳转中传递requestCode的之后根据onActivityResult(int requestCode, int resultCode, Intent data)中返回的resultCode遍历关闭Activity
思路:使用startActivityForResult(intent, requestCode)方法跳转,并且通过
描述:这里我把这些广播的初始化都写在了基类BaseActivity里面便于查看。
代码:
之后在流程的Activity中调用带请求码的Intent跳转意图。
在最后完成注册流程的时候通过以下方式返回:
优缺点:
方法:方法有人说可以使用抛出异常来退出,可是这样会影响到用户体验,所以不推荐
五、title管理及基类
常见的Android应用每个Activity或者Fragment都会带有一个Title栏。最普通的就是每个Activity的布局文件中都写一个title。但是这样管理起来比较麻烦,因为每个activity的title栏其实看起来都差不多,基本都包含有返回功能,一个textview描述当前页面,最右侧会是一个更多或者搜索之类的功能按钮。这样我们其实可以使用一个通用的布局,在所有的activity的父类中直接控制title的样式。
1.首先是BaseActivity作为所有Activity的父类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
|
public abstract class BaseActivity extends Activity { public LayoutInflater inflater; public Resources mResources; public Context mContext; public View rootView; private View titleView; private LinearLayout.LayoutParams params; public int layoutId; @Override protected void onCreate(Bundle savedInstanceState) { super .onCreate(savedInstanceState); inflater = getLayoutInflater(); layoutId = getContentView(); rootView = inflater.inflate(layoutId, null ); mContext = this ; mResources = mContext.getResources(); params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ( int ) mResources.getDimension(R.dimen.common_title_height)); setContentView(rootView); findViewById(); initTitleView(); initData(); } private void initTitleView() { titleView = TitleManager.getInstance( this ).initTitleView(layoutId); ((ViewGroup) rootView).addView(titleView, 0 , params); } /** * 绑定控件id */ protected abstract void findViewById(); protected abstract void initData(); /** * 初始化控件 */ protected abstract int getContentView(); } |
2.接着是titlemanager类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
|
public class TitleManager implements View.OnClickListener { private static TitleManager uniqueInstance = null ; private Activity context; private View titleView; private LayoutInflater inflater; private TitleManager(Activity context) { this .context = context; inflater = context.getLayoutInflater(); } public static TitleManager getInstance(Activity context) { if (uniqueInstance == null ) { uniqueInstance = new TitleManager(context); } return uniqueInstance; } public ImageView mCommonTitleLeft; public TextView mCityNameTextView; public TextView mTitleTextView; public ImageView mSearch; public ImageView mFavorite; public ImageView mShare; public View initTitleView( int layoutId) { titleView = inflater.inflate(R.layout.view_product_common_title, null ); mCommonTitleLeft = (ImageView) titleView.findViewById(R.id.common_title_left); mCommonTitleLeft.setOnClickListener( this ); mCityNameTextView = (TextView) titleView.findViewById(R.id.activity_product_home_left); mCityNameTextView.setOnClickListener( this ); mTitleTextView = (TextView) titleView.findViewById(R.id.common_title_center); mSearch = (ImageView) titleView.findViewById(R.id.common_title_search); mSearch.setOnClickListener( this ); mFavorite = (ImageView) titleView.findViewById(R.id.details_product_favorite_img); mFavorite.setOnClickListener( this ); mShare = (ImageView) titleView.findViewById(R.id.details_product_shear_img); mShare.setOnClickListener( this ); switch (layoutId) { case R.layout.main: mCityNameTextView.setVisibility(View.VISIBLE); mSearch.setVisibility(View.VISIBLE); mTitleTextView.setText(R.string.title_activity_main); break ; case R.layout.main1: mCommonTitleLeft.setVisibility(View.VISIBLE); mTitleTextView.setText(R.string.title_activity_main1); break ; case R.layout.main2: mCommonTitleLeft.setVisibility(View.VISIBLE); mFavorite.setVisibility(View.VISIBLE); mTitleTextView.setText(R.string.title_activity_main2); break ; case R.layout.main3: mCommonTitleLeft.setVisibility(View.VISIBLE); mShare.setVisibility(View.VISIBLE); mTitleTextView.setText(R.string.title_activity_main3); break ; default : mCityNameTextView.setVisibility(View.GONE); mSearch.setVisibility(View.GONE); mCommonTitleLeft.setVisibility(View.VISIBLE); mFavorite.setVisibility(View.GONE); mShare.setVisibility(View.GONE); break ; } return titleView; } @Override public void onClick(View v) { switch (v.getId()) { case R.id.common_title_left: context.finish(); break ; case R.id.common_title_search: Toast.makeText(context, "search" , Toast.LENGTH_SHORT).show(); break ; } } } |
标签:
原文地址:http://www.cnblogs.com/ymczxy/p/4710331.html