android四大组件之activity
Activity是四大组件中最重要的一个组件,以下将从activity生命周期,任务栈及启动模式/设置flag,数据/对象传递及startactivtyforresult的使用,安全退出,Title及基类等几个方面来详述activity的特性。
[转]http://blog.csdn.net/lijianli9/article/details/19072623
一、activity的生命周期:
1. Activity状态
激活状态 : Activity出于前台 , 栈顶位置;
暂停状态 : 失去了焦点 , 但是用户仍然可以看到 , 比如弹出一个对话框 , 后面的Activity出于暂停状态;
停止状态 : 被其它的Activity覆盖 , 用户不可见 , 但是仍然存在;
2.Activity操作生命周期的方法
onCreate() : 初始化一些成员变量 , 如View等 , 此时进入停止状态;
onStart() : 被用户可见之前调用 , 调用之后进入暂停状态 , 如果不满足条件我们不想让用户进入应用 , 可以在这里进行限制 , finish掉该Activity;
onResume() : 在与用户交互之前调用 , 调用之后进入激活状态;
onPause() : 激活另一个Activity时调用 , 调用之后进入暂停状态 , 界面可见 , 失去焦点; 该操作用来保存当前Activity数据;
onStop() : Activity被覆盖前调用 , 调用之后该Activity不可见; 该方法用来关闭旧的Activity , 注意是完全不可见的时候才会调用这个方法;
onDestroy() : Activity被销毁前调用 ;
注意 : 在暂停状态 和 停止状态 , 如果内存紧张 , 该Activity会被系统回收;也就是除了onResume()和onDestroy(),其他几个方法中都有可能被回收
3.Activity运作流程
(1)第一次启动Activity A
首先调用onCreate()方法创建Activity进入停止状态 -> 调用onStart()方法进入暂停状态 -> 调用onResume()方法进入激活状态;
(2)从Activity A 跳转到 Activity B
A先执行onPause()方法进入暂停状态 -> B执行onCreate()方法进入停止状态 -> B执行onStart()方法进入暂停状态 -> B执行onResume()方法进入激活状态 -> A被完全覆盖执行onStop()方法进入停止状态;
(3)从ActivityB 回到 Activity A
B执行onPause()方法进入暂停状态 -> A调用onRestart()方法进入停止状态 -> A调用onStart()方法进入暂停状态 -> A调用onResume()方法进入激活状态 -> B被覆盖调用onStop()方法进入停止状态 -> B执行onDestroy()方法销毁
这里注意Activity的栈是不可逆的 , 只能后退 , 不能前进 , 回退后 , 原来的栈顶的Activity就马上销毁了.
[转]http://blog.csdn.net/vipzjyno1/article/details/25463457
二.Activity启动模式、任务栈及标志位flag
1.什么是栈
栈
栈是一种常用的数据结构,栈只允许访问栈顶的元素,栈就像一个杯子,每次都只能取杯子顶上的东西,而对于栈就只能每次访问它的栈顶元素,从而可以达到保护栈顶元素以下的其他元素.”先进后出”或”后进先出”就是栈的一大特点,先进栈的元素总是要等到后进栈的元素出栈以后才能出栈.递归就是利用到了系统栈,暂时保存临时结果,对临时结果进行保护.
定义栈(Stack)
栈的定义栈(Stack)是限制仅在表的一端进行插入和删除运算的线性表。(1)通常称插入、删除的这一端为栈顶(Top),另一端称为栈底(Bottom)。 (2)当表中没有元素时称为空栈。(3)栈为后进先出(Last In First Out)的线性表,简称为LIFO表。栈的修改是按后进先出的原则进行。每次删除(退栈)的总是当前栈中"最新"的元素,即最后插入(进栈)的元素,而最先插入的是被放在栈的底部,要到最后才能删除。
栈的操作:压栈、弹栈
2.Activity中的栈
Android的管理主要是通过Activity栈来进行,当一个Activity启动时,系统会根据其配置将它压入到一个特定的栈中,系统处于运行状态。
当用户点击返回或则FINISH()了该Activity,那么它便会被从栈中压出,随之摧毁。
按照Activity的生命周期可以知道,如果当前显示的栈中Activity没有被摧毁,那么打开新的Activity时候,会将新打开的压入到栈,原来的根据其显示情况选择状态变化(原Activity依旧可见,变为暂停状态(Paused),如果被完成遮住了,转变为停止状态(Stopped))。
3.Task
4.Activity启动模式
"singleTop"
"singleTask"
"singleInstance"
以下举例说明它们的区别:
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。
5.Activity栈和Task联系
6.Intent Flags
7.Activity相关属性taskAffinity
Activity为Task拥有的一个affinity。拥有相同的affinity的Activity理论上属于相同的Task(在用户的角度是相同的“应用程序”)。Task的affinity是由它的根Activity决定的。
affinity决定两件事情——Activity重新宿主的Task(参考allowTaskReparenting特性)和使用FLAG_ACTIVITY_NEW_TASK标志启动的Activity宿主的Task。
默认情况,一个应用程序中的所有Activity都拥有相同的affinity。捏可以设定这个特性来重组它们,甚至可以把不同应用程序中定义的Activity放置到相同的Task中。为了明确Activity不宿主特定的Task,设定该特性为空的字符串。
如果这个特性没有设置,Activity将从应用程序的设定那里继承下来(参考<application>元素的taskAffinity特性)。应用程序默认的affinity的名字是<manifest>元素中设定的package名。
这一节介绍一下activity之间参数传递。我们知道用intent可以实现activity之间相互跳转,在跳转的同时我们不免也需要传递一些参数,下面就介绍一下如何在一个activity里传递参数,在另一个activity里接受参数。
activity之间有两种参数传递形式:一种是一个activity启动另一个activity的时候传递数据到另一个activity,然后在activity中接受到数据,做相应处理。另一种是一个activity启动另个一activity传递数据,当另个一activity窗口关闭后,在传递数据到启动它的那个activity。
我们先看一下第一种方式
首先先建立一个ActivityDemo项目:
- public class MainDemoActivity extends Activity {
- private Button button1,button2;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- button1=(Button) this.findViewById(R.id.button1);
- button2=(Button) this.findViewById(R.id.button2);
- button1.setOnClickListener(new MyListener());
- button2.setOnClickListener(new MyListener());
- }
- private class MyListener implements View.OnClickListener{
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent intent=new Intent();
- if(v==button1){
- intent.setClass(MainDemoActivity.this, FirstDemoActivity.class);
- }else if(v==button2){
- intent.setClass(MainDemoActivity.this, ResultDemoActivity.class);
- }
- startActivity(intent);
- }
- }
- }
接着给出main.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
- <Button
- android:id="@+id/button1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="传递参数不得到返回值" />
- <Button
- android:id="@+id/button2"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="传递参数得到返回值" />
- </LinearLayout>
看一下第一种是怎么传递参数的:
- public class FirstDemoActivity extends Activity {
- private Button button3;
- private EditText editText;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.first);
- button3=(Button) this.findViewById(R.id.button3);
- editText=(EditText) this.findViewById(R.id.editText1);
- button3.setOnClickListener(new View.OnClickListener() {
- public void onClick(View v) {
- // TODO Auto-generated method stub
- String content=editText.getText().toString();
- Intent intent=new Intent(FirstDemoActivity.this,SecondDemoActivity.class);
- //可以把要传递的参数放到一个bundle里传递过去,bundle可以看做一个特殊的map.
- Bundle bundle=new Bundle();
- bundle.putString("result", "第一个activity的内容");
- bundle.putString("content",content);
- intent.putExtras(bundle);
- //也可以用这种方式传递.
- //intent.putExtra("result", "第一个activity的内容");
- startActivity(intent);
- }
- });
- }
- }
看一下在SecondDemoActivity中怎么接受参数:
- public class SecondDemoActivity extends Activity {
- private TextView textView;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- // TODO Auto-generated method stub
- super.onCreate(savedInstanceState);
- setContentView(R.layout.second);
- textView=(TextView) this.findViewById(R.id.textView3);
- Intent intent=getIntent();
- String result=intent.getStringExtra("result");
- String content=intent.getStringExtra("content");
- textView.setText(result+" : "+content);
- }
- }
启动,看一下运行效果:
点击发送按钮:
OK! 成功。
接下来看看第二种方式:
先看一下页面的布局文件:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="vertical" >
- <TextView
- android:id="@+id/text"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:text="@string/hello" />
- </LinearLayout>
核心代码:
- public class ResultDemoActivity extends Activity {
- /** Called when the activity is first created. */
- private TextView text;
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.result);
- text=(TextView)this.findViewById(R.id.text);
- pickContact();
- }
- private void pickContact(){
- Intent intent=new Intent(Intent.ACTION_PICK,ContactsContract.Contacts.CONTENT_URI);
- //在这里也可以传递一些参数
- //intent.putExtra(name, value)
- //第二个参数就是onActivityResult 里得第一个参数。
- startActivityForResult(intent,1);
- }
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- // TODO Auto-generated method stub
- if(resultCode==Activity.RESULT_OK && requestCode==1){
- Cursor cusor=this.getContentResolver()
- .query(data.getData(), new String[]{ContactsContract.Contacts.DISPLAY_NAME},
- null, null, null);
- if(cusor.moveToFirst()){
- String str=cusor.getString(cusor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
- text.setText(str);
- }
- }
- }
- }
代码我想大家都看的懂吧!不懂得看我以前的使用Content Provider得到联系人信息这一节
看一下运行效果:
这是我通讯录的联系人。点击listview:
返回到了ResultDemoActivity并得到了联系人的名字。
xml序列化传递对象:
1:Serializable方式
传递一个对象
2:Parcelable方式
传递一个对象、传递多个对象(ArrayList<Object>)
方式一:Serializable
传递类:
- public class CustomeClass implements Serializable{
- /**
- *
- */
- private static final long serialVersionUID = -7060210544600464481L;
- private String name;
- private String id;
- private int age;
- private String sex;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- }
发送部分:
- CustomeClass cc = new CustomeClass();
- cc.setAge(21);
- cc.setId("123456");
- cc.setName("mingkg21");
- cc.setSex("男");
- Intent intent = new Intent(this, PersonInfo.class);
- intent.putExtra("PERSON_INFO", cc);
- startActivity(intent);
接收部分:
- Intent intent = getIntent();
- CustomeClass cc = CustomeClass)intent.getSerializableExtra("PERSON_INFO");
- setTextView(R.id.id, cc.getId());
- setTextView(R.id.name, cc.getName());
- setTextView(R.id.sex, cc.getSex());
- setTextView(R.id.age, String.valueOf(cc.getAge()));
方式二:Parcelable
传递类:
- public class CustomeParcelable implements Parcelable {
- private String name;
- private String id;
- private int age;
- private String sex;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getId() {
- return id;
- }
- public void setId(String id) {
- this.id = id;
- }
- public int getAge() {
- return age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- public static final Parcelable.Creator<CustomeParcelable> CREATOR = new Creator<CustomeParcelable>(){
- public CustomeParcelable createFromParcel(Parcel source) {
- // TODO Auto-generated method stub
- CustomeParcelable cus = new CustomeParcelable();
- cus.name = source.readString();
- cus.id = source.readString();
- cus.age = source.readInt();
- cus.sex = source.readString();
- return cus;
- }
- public CustomeParcelable[] newArray(int size) {
- // TODO Auto-generated method stub
- return new CustomeParcelable[size];
- }
- };
- public int describeContents() {
- // TODO Auto-generated method stub
- return 0;
- }
- public void writeToParcel(Parcel dest, int flags) {
- // TODO Auto-generated method stub
- dest.writeString(name);
- dest.writeString(id);
- dest.writeInt(age);
- dest.writeString(sex);
- }
- }
发送部分:
- CustomeParcelable cc = new CustomeParcelable();
- cc.setAge(21);
- cc.setId("123456");
- cc.setName("mingkg21");
- cc.setSex("男");
- Intent intent = new Intent(this, PersonInfo.class);
- intent.putExtra("PERSON_INFO", cc);
- startActivity(intent);
接受部分:
- Intent intent = getIntent();
- CustomeParcelable cc = intent.getParcelableExtra("PERSON_INFO");
- setTextView(R.id.id, cc.getId());
- setTextView(R.id.name, cc.getName());
- setTextView(R.id.sex, cc.getSex());
- setTextView(R.id.age, String.valueOf(cc.getAge()));
以上为Parcelable传递一个对象,若要实现传递多个对象,
传递部分:
- Bundle bundle = new Bundle();
- bundle.putParcelableArrayList("mP3TagForNetDTOs",mP3TagForNetDTOs);
- msg.setData(bundle);
- endDocNotice.sendMessage(msg);
接受部分:
- Bundle bundle = msg.getData();
- mP3TagForNetDTOs = bundle.getParcelableArrayList("mP3TagForNetDTOs");
四.多个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 与 栈 的关联分析
具体方案
方案1
方法:采用FLAG_ACTIVITY_CLEAR_TOP退出整个程序(多activity)
思路:通过Intent的Flags来控制堆栈去解决
android中,每打开一个Activity,便会在栈中加入一个Activity,当该Activity被摧毁后,栈中便移除了它,并且栈中的Activity是按照开打的先后顺序依次排排列的。
Android的窗口类提供了历史栈,我们可以通过stack的原理来巧妙的实现,这里我们在A窗口打开B窗口时在Intent中直接加入标 志 Intent.FLAG_ACTIVITY_CLEAR_TOP,这样开启B时将会清除该进程空间的所有Activity。
代码:
在注册流程最后的FourthStep.class中,点击完成注册点击事件
- btn_finish.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- Intent intent = new Intent(INTENT_METHOD_FIRST_SINGUP);
- intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
- }
- });
其中的 INTENT_METHOD_FIRST_SINGUP 是登录界面的Intent隐式Action。
优缺点:
优:使用对栈的巧妙利用,不会赞成内存无故占用等问题,个人认为这个方法是首选。
方案2
方法:通过堆栈管理器去管理
思路:通过堆栈管理器,对Stack进的存储Activity进行操作(推入,推出,弹出)
代码:
- public class StackManager {
- /**
- * Stack 中对应的Activity列表 (也可以写做 Stack<Activity>)
- */
- private static Stack mActivityStack;
- private static StackManager mInstance;
- /**
- * @描述 获取栈管理工具
- * @return ActivityManager
- */
- public static StackManager getStackManager() {
- if (mInstance == null) {
- mInstance = new StackManager();
- }
- return mInstance;
- }
- /**
- * 推出栈顶Activity
- */
- public void popActivity(Activity activity) {
- if (activity != null) {
- activity.finish();
- mActivityStack.remove(activity);
- activity = null;
- }
- }
- /**
- * 获得当前栈顶Activity
- */
- public Activity currentActivity() {
- //lastElement()获取最后个子元素,这里是栈顶的Activity
- if(mActivityStack == null || mActivityStack.size() ==0){
- return null;
- }
- Activity activity = (Activity) mActivityStack.lastElement();
- return activity;
- }
- /**
- * 将当前Activity推入栈中
- */
- public void pushActivity(Activity activity) {
- if (mActivityStack == null) {
- mActivityStack = new Stack();
- }
- mActivityStack.add(activity);
- }
- /**
- * 弹出指定的clsss所在栈顶部的中所有Activity
- * @clsss : 指定的类
- */
- public void popTopActivitys(Class clsss) {
- while (true) {
- Activity activity = currentActivity();
- if (activity == null) {
- break;
- }
- if (activity.getClass().equals(clsss)) {
- break;
- }
- popActivity(activity);
- }
- }
- /**
- * 弹出栈中所有Activity
- */
- public void popAllActivitys() {
- while (true) {
- Activity activity = currentActivity();
- if (activity == null) {
- break;
- }
- popActivity(activity);
- }
- }
- }
之后在注册流程中的对应步骤的Activity的onCreate()中把当前Activity推入栈列表,完成注册流程后,弹出栈列表中流程所涉及的Activity。
优缺点:
缺:如果处理不当,容易造成不在当前界面的Activity被全局引用而摧毁不掉,内存得不到释放,从而无故占用不必要的内存。
方案3:
方法:全局记录打开的Activity或通过一个自定义的类去管理打开的Activity
思路:通过在Application中用一个列表来记录当前所打开的Activity,根据需求去遍历finish()。
描述:和方案2有点类似。
代码:
- public class AppApplication extends Application {
- private static AppApplication mAppApplication;
- /** 当前打开的activity列表 */
- public ArrayList<Activity> activityList;
- @Override
- public void onCreate() {
- // TODO Auto-generated method stub
- super.onCreate();
- mAppApplication = this;
- }
- /** 获取Application */
- public static AppApplication getApp() {
- if (mAppApplication == null) {
- mAppApplication = new AppApplication();
- }
- return mAppApplication;
- }
- /** 添加当前Activity 到列表中 */
- public void addActivity(Activity acitivity) {
- if(activityList == null){
- activityList = new ArrayList<Activity>();
- }
- activityList.add(acitivity);
- }
- /** 清空列表,取消引用*/
- public void clearActivity(){
- activityList.clear();
- }
- /** 遍历退出所有Activity */
- public void exit() {
- for (Activity activity : activityList) {
- activity.finish();
- }
- clearActivity();//千万记得清空取消引用。
- System.exit(0);
- }
使用流程和方法2类似。
优缺点:
缺:如果处理不当,容易造成不在当前界面的Activity被全局引用而摧毁不掉,内存得不到释放,从而无故占用不必要的内存。
方案4
方法:使用广播机制解决
思路:通过Activity创建的时候,设置监听广播,在注册流程最后步完成注册时候,发送广播进行遍历finish().
描述:这里我把这些广播的初始化都写在了基类BaseActivity里面,便于维护。
代码:
- /**
- * 初始化退出广播
- */
- public void initFinishReceiver() {
- IntentFilter filter = new IntentFilter();
- filter.addAction(INIENT_FINISH);
- registerReceiver(mFinishReceiver, filter);
- }
- /**
- * 监听是否退出的广播
- */
- public BroadcastReceiver mFinishReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (INIENT_FINISH.equals(intent.getAction())) {
- finish();
- }
- }
- };
在流程中的每步Activity中,初始化广播,之后在点击完成注册时候,发送广播
- btn_finish.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- getApplicationContext().sendBroadcast(new Intent(INIENT_FINISH));
- }
- });
优缺点:
缺:开启过多的广播监听,觉得会浪费资源。
方案5:
方法:通过Activity跳转中传递requestCode的之后根据onActivityResult(int requestCode, int resultCode, Intent data)中返回的resultCode遍历关闭Activity
思路:使用startActivityForResult(intent, requestCode)方法跳转,并且通过
描述:这里我把这些广播的初始化都写在了基类BaseActivity里面便于查看。
代码:
- /** 关闭时候的requestCode请求码 */
- public final static int FINISH_REQUESTCODE = 1;
- /** 关闭时候的resultCode请求码 */
- public final static int FINISH_RESULTCODE = 1;
- /**
- * 方法5通过回调关闭的时候用到
- */
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- // TODO Auto-generated method stub
- if(requestCode == FINISH_REQUESTCODE ){
- if(resultCode == FINISH_RESULTCODE){
- setResult(FINISH_RESULTCODE);
- finish();
- }
- }
- super.onActivityResult(requestCode, resultCode, data);
- }
之后在流程的Activity中调用带请求码的Intent跳转意图。
- startActivityForResult(new Intent(getApplicationContext(), SecondStep.class),FINISH_REQUESTCODE);
在最后完成注册流程的时候通过以下方式返回:
- btn_finish.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- // TODO Auto-generated method stub
- setResult(FINISH_RESULTCODE);
- finish();
- }
- });
优缺点:
方案6(不推荐)
方法:方法有人说可以使用抛出异常来退出,可是这样会影响到用户体验,所以不推荐
五、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 ; } } } |