标题中引号的内容,相信各位Android程序员会碰到这样的需求。特别是当一个功能有多个入口的时候,更种跳转会让人抓狂。有时候我们会利用Activity的SingleTask模式来完成清栈操作,但当业务场景变的复杂的时候,就需要我们考虑其他方式了。
情景一
Activity的跳转路径为:
A->B->C->D->E->A。
最终要求存在栈里面的Activity只有A。
实现
通过设置Activity A为SingleTask模式可以完成该跳转操作(当然前提是要求所有Activity在同一个Task里面)。同时,我们也可以通过自定义一个Activity栈来完成该操作。代码如下:
import android.app.Activity;
import java.util.ArrayList;
/**
* help to manager activity stack
* @author kisson
*/
public class ActivityStackManager {
private static ArrayList<Activity> sActivityList = new ArrayList<>();
private static class ActivityStackManagerHolder {
private static ActivityStackManager sInstance = new ActivityStackManager();
}
public static ActivityStackManager getInstance() {
return ActivityStackManagerHolder.sInstance;
}
public void addActivity(Activity activity) {
sActivityList.add(activity);
}
/**
* back to target activity
*
* @param addTime the add time of target activity
* @return true if back to target activity successfully
*/
public boolean back2TargetActivity(String addTime) {
if (isTargetActivityExist(addTime)) {
for (int i = sActivityList.size() - 1; i >= 0; i--) {
String var = ((BaseActivity) sActivityList.get(i)).getAddTime();
if (!var.equals(addTime)) {
popActivityFromStack(sActivityList.get(i));
} else {
return true;
}
}
}
return false;
}
/**
* back to target activity
*
* @param indexActivityClass the class of target activity
* @return true if back to target activity successfully
*/
public boolean back2TargetActivity(Class<Activity> indexActivityClass) {
if (isTargetActivityExist(indexActivityClass)) {
for (int i = sActivityList.size() - 1; i >= 0; i--) {
if (sActivityList.get(i).getClass() != indexActivityClass) {
popActivityFromStack(sActivityList.get(i));
} else {
return true;
}
}
}
return false;
}
private boolean isTargetActivityExist(String addTime) {
for (Activity activity : sActivityList) {
if(activity == null){
continue;
}
if (((BaseActivity) activity).getAddTime().equals(addTime)) {
return true;
}
}
return false;
}
private boolean isTargetActivityExist(Class<Activity> targetActivityClass) {
for (Activity activity : sActivityList) {
if(activity == null){
continue;
}
if (activity.getClass() == targetActivityClass) {
return true;
}
}
return false;
}
private void popActivityFromStack(Activity activity) {
if (activity != null && !activity.isFinishing()) {
activity.finish();
sActivityList.remove(activity);
}
}
public void removeActivity(Activity activity) {
sActivityList.remove(activity);
}
}
以上写的Activity栈管理器比较简单,我们可以根据需求进行拓展。接着定义一个BaseActivity类,来完成入栈和出栈等相关操作,代码如下。
import android.app.Activity;
import android.os.Bundle;
import android.os.SystemClock;
/**
* Created by kisson on 16/6/7.
*/
public class BaseActivity extends Activity {
private String addTime;
public String getAddTime() {
return addTime;
}
public void setAddTime(String addTime) {
this.addTime = addTime;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setAddTime(String.valueOf(SystemClock.currentThreadTimeMillis()));
ActivityStackManager.getInstance().addActivity(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
ActivityStackManager.getInstance().removeActivity(this);
}
}
这里在BaseActivity中定义了addTime变量,那么它的作用什么?
比如Activity的跳转路径为:
A->B->C->D->B'->E。
在该跳转路径上Activity B 出现两次(Activity B的启动模式为standard),虽然它们是同一个Activity,但是是不同的的实例,因此通过Class来区分就显得不够用了。所以,在这里添加addTime变量,用于保证Activity实例的唯一性。
接着,我们需要实现一个辅助类用于完成“情景一”的跳转。
package com.dighammer.kisson.goback;
import android.app.Activity;
import java.util.ArrayList;
import java.util.List;
/**
* Created by kisson on 16/6/8.
*/
public class ActivityPathManager {
/**
* 这里用数组记录源Activity而不是单独用一个String,是因为:在某一个跳转路径上可能有多个注册源Activity行为
* 比如A->B->C-D-A,在A中进行注册源Activity,
* 同时另外一条链路M->N->B->C->D->M(当然这两条链路是不可能同时发生的),需要在B中注册源Activity。但是这两条链路有重合部分,
* 如果仅仅用String来表示addTime,会存在覆盖的情况,因此用数组来保存addTime,但是只有第一条数据有效。
**/
private static List<String> sAddTimeList = new ArrayList<>();
private static List<Class<Activity>> sActivityClassList = new ArrayList<>();
private static class ActivityPathManagerHolder {
private static ActivityPathManager sInstance = new ActivityPathManager();
}
public static ActivityPathManager getInstance() {
return ActivityPathManagerHolder.sInstance;
}
/**
* 注册源Activity
*
* @param addTime Activity的创建时间,可以唯一表示某一Activity
*/
public void registerSourceActivity(String addTime) {
sAddTimeList.add(addTime);
}
/**
* 注册源Activity
*
* @param indexClass Activity的类名
*/
public void registerSourceActivity(Class<Activity> indexClass) {
sActivityClassList.add(indexClass);
}
/**
* 当从源Activity通过任意跳转路径到达目标Activity时,调用此方法后可以返回到源Activity
*
* @return 如果是true,直接跳转到源Activity;如果是false,走原有逻辑
*/
public boolean back2SourceActivity() {
if (!sAddTimeList.isEmpty()) {
ActivityStackManager.getInstance().back2TargetActivity(sAddTimeList.get(0));
clearAddTime();
return true;
}
return false;
}
/**
* 当从源Activity通过任意跳转路径到达目标Activity时,调用此方法后可以返回到源Activity
*
* @return 如果是true,直接跳转到源Activity;如果是false,走原有逻辑
*/
public boolean back2SourceActivity2() {
if (!sActivityClassList.isEmpty()) {
ActivityStackManager.getInstance().back2TargetActivity(sActivityClassList.get(0));
clearClass();
return true;
}
return false;
}
/**
* 当从源Activity通过任意跳转路径到达目标Activity时,调用此方法后可以返回到源Activity,此方法不需要注册Activity
*
* @param addTime 源Activity的添加时间
* @return 如果是true,直接跳转到源Activity;如果是false,走原有逻辑
*/
public boolean back2SourceActivity(String addTime) {
if (addTime != null) {
ActivityStackManager.getInstance().back2TargetActivity(addTime);
return true;
}
return false;
}
/**
* 当从源Activity通过任意跳转路径到达目标Activity时,调用此方法后可以返回到源Activity,此方法不需要注册Activity
*
* @param indexClass 源Activity的类
* @return 如果是true,直接跳转到源Activity;如果是false,走原有逻辑
*/
public boolean back2SourceActivity(Class<Activity> indexClass) {
if (indexClass != null) {
ActivityStackManager.getInstance().back2TargetActivity(indexClass);
return true;
}
return false;
}
private void clearAddTime() {
sAddTimeList.clear();
}
private void clearClass() {
sActivityClassList.clear();
}
/**
* 清除所有已经注册Activity的addTime
* notice:在你的源Activity的onCreate和onRestart方法调用该方法!
*/
public void unregisterSourceActivity(String addTime) {
sAddTimeList.remove(addTime);
}
/**
* 清除所有已经注册Activity的Class
* notice:在你的源Activity的onCreate和onRestart方法调用该方法!
*/
public void unregisterSourceActivity(Class<Activity> indexClass) {
sActivityClassList.remove(indexClass);
}
}
用法
在源Activity中通过调用ActivityPathManager的registerSourceActivity方法进行注册(注意在源Activity的onCreate和onRestart方法进行注销),比如。
public void onClick(View view) {
startActivity(new Intent(SourceActivity.this, AActivity.class));
ActivityPathManager.getInstance().registerSourceActivity(getAddTime());
}
在最终跳转到的目标Activity通过调用ActivityPathManager的back2SourceActivity方法返回到源Activity,比如。
public void onClick(View view){
ActivityPathManager.getInstance().back2SourceActivity();
}
最终的结果可以成功返回到源Activity。
情景二
本文所实现的“从哪来回哪去”功能并不能顾及到所有跳转情况,但是我们可以根据需求在此基础上进行拓展。
比如跳转路径为A->B->C->D->E->F。
最终要求栈里只有A和F,并且F后退是返回到A的。
这种跳转需求,Activity的四种启动模式就无法搞定了。
但是我们可以增加ActivityPathManager和ActivityStackManager类中的方法,来完成相应的功能。
在ActivityStackManager类中增加back2TargetActivityExceptTop方法,代码如下。
/**
* back to target activity but do not pop the top activity
*
* @param addTime the add time of target activity
* @return true if back to target activity successfully
*/
public boolean back2TargetActivityExceptTop(String addTime) {
if (isTargetActivityExist(addTime)) {
for (int i = sActivityList.size() - 2; i >= 0; i--) {
String var = ((BaseActivity) sActivityList.get(i)).getAddTime();
if (!var.equals(addTime)) {
popActivityFromStack(sActivityList.get(i));
} else {
return true;
}
}
}
return false;
}
通用在ActivityPathManager类中增加back2SourceActivityExceptTop方法,代码如下:
public boolean back2SourceActivityExceptTop() {
if (!sAddTimeList.isEmpty()) {
ActivityStackManager.getInstance().back2TargetActivityExceptTop(sAddTimeList.get(0));
clearAddTime();
return true;
}
return false;
}
最后
欢迎大家来提出宝贵意见,或者某些情景下,本文功能无法实现的!