前言

今日项目中有这样一个需求,需要一套类似与目前所有业务逻辑的新应用,基于框架、数据模板都相同,但是对外提供内容不同,所以必须有两个入口(看起来是两个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入口了

android里的栈是什么意思 android activity栈管理_Stack

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状态

android里的栈是什么意思 android activity栈管理_ide_02

android里的栈是什么意思 android activity栈管理_android里的栈是什么意思_03

4.其他

整体设计基于所有Activity继承BaseActivity,并且在AndroidManifest中指定的两个入口,皆有对应的栈,因此是只要是该activity启动跳转的其他activity,若不指定taskAffinity则默认还是当前stack。因项目中涉及activity不多,暂时没有发现还有什么问题,有问题欢迎讨论