前言
今日项目中有这样一个需求,需要一套类似与目前所有业务逻辑的新应用,基于框架、数据模板都相同,但是对外提供内容不同,所以必须有两个入口(看起来是两个app),因此经过技术评审后决定还是使用同一工程,但是两个入口。其中实现问题不大,主要是activity栈的管理,默认情况下同一应用启动的activity都会在同一个栈中,这样就会发生如果打开两个入口后,其中两种模式下的activity都会混在一起,不能达到业务区分的效果。这篇重点介绍自定义管理activity栈的一种方式。
大纲
1.双入口实现
2.activity栈管理
3.activity栈配置
4.其他
正文
1.双入口实现
主要是对AndroidManifest.xml进行简单设置,假设有两个入口,分别为AppA和AppB,其中他们各有两个activity(A1、A2;B1、B2),将A1和B1分别设为两个启动的activity,并指定栈为包名.a和包名.b,即设置taskAffinity。如下所设置
<!--App A-->
<activity android:name=".appA.A1Activity"
android:launchMode="singleTop"
android:label="@string/app_nameA"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:taskAffinity="com.zidian.myactivitystackmanager.a">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".appA.A2Activity"
android:launchMode="singleTop"/>
<!--App B-->
<activity android:name=".appB.B1Activity"
android:launchMode="singleTop"
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:label="@string/app_nameB"
android:taskAffinity="com.zidian.myactivitystackmanager.b">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name=".appB.B2Activity"
android:launchMode="singleTop"/>
这样,运行后就会有两个Lancher入口了
2.activity栈管理
然后新建一个管理类ActivityStackManager,单例模式,并有一个map管理不同stack,key为taskId,value为stack实体;然后再有一个activity对象存储当前显示在前台的activity。
private static final ActivityStackManager IN = new ActivityStackManager();
private SparseArray<Stack<BaseActivity>> stackSparseArray;
private BaseActivity currentActivity;
private ActivityStackManager() {
stackSparseArray = new SparseArray<>();
}
public static ActivityStackManager getInstance() {
return IN;
}
对外提供几种方法:addActivity、removeActivity、setCurrentActivity、startActivity、finshActivity、getStack
/**
* BaseActivity onCreate
* @param activity
*/
public void addActivity(BaseActivity activity){
getStack(activity).push(activity);
}
/**
* BaseActivity onDestroy
* @param activity
*/
public void removeActivity(BaseActivity activity){
getStack(activity).remove(activity);
}
/**
* BaseActivity onResume
* @param currentActivity
*/
public void setCurrentActivity(BaseActivity currentActivity) {
this.currentActivity = currentActivity;
}
/**
* 可以代替activity.startActivity
* @param activity
* @param targetClass
*/
public void startActivity(BaseActivity activity, Class<?> targetClass){
Intent intent = new Intent(activity, targetClass);
activity.startActivity(intent);
}
/**
* 可以代替activity.finish
*/
public void finshActivity(){
if (currentActivity != null) {
finshActivity(currentActivity);
}
}
public void finshActivity(BaseActivity activity){
if (getStack(activity).size() > 1){
activity.finish();
}else {
Timber.e("current activity is last in stack");
}
}
/**
* 返回当前activity的栈
* @param activity ? extends BaseActivity
* @return Stack
*/
private Stack<BaseActivity> getStack(BaseActivity activity){
Stack<BaseActivity> stack = stackSparseArray.get(activity.getTaskId());
if (stack == null) {
stack = new Stack<>();
stackSparseArray.put(activity.getTaskId(), stack);
}
return stack;
}
至此,一个activity栈管理类准备完毕。
3.activity栈配置
基于抽象设计理念,所有操作皆在BaseActivity内完成即可
onCreate:addActivity
onResume:setCurrentActivity
onDestroy:removeActivity
onBackPressed:finshActivity
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutId());
afterOnCreate();
ActivityStackManager.getInstance().addActivity(this);
}
@Override
protected void onResume() {
super.onResume();
ActivityStackManager.getInstance().setCurrentActivity(this);
}
@Override
protected void onDestroy() {
ActivityStackManager.getInstance().removeActivity(this);
super.onDestroy();
}
@Override
public void onBackPressed() {
ActivityStackManager.getInstance().finshActivity(this);
}
其中在back键回退时交给ASM处理判断,若当前栈仅有当前一个activity则不退出,则可以实现不同栈之间不会相互回退跳转问题。
使用adb shell dumpsys activity activities命令查看当前activity状态
4.其他
整体设计基于所有Activity继承BaseActivity,并且在AndroidManifest中指定的两个入口,皆有对应的栈,因此是只要是该activity启动跳转的其他activity,若不指定taskAffinity则默认还是当前stack。因项目中涉及activity不多,暂时没有发现还有什么问题,有问题欢迎讨论