Android中一個(gè)Activity關(guān)閉另一個(gè)Activity或者在一個(gè)Activity中關(guān)閉多個(gè)Activity


前言

最近項(xiàng)目中涉及需要在一個(gè)Activity中關(guān)閉另一個(gè)Activity或者在一個(gè)Activity中關(guān)閉多個(gè)Activity的需求,不涉及到應(yīng)用的退出。自己首先想了一些方案,同時(shí)也查了一些方案,就各個(gè)方案比較下優(yōu)劣。


方案一

廣播的方式

這個(gè)是最容易想到的,同時(shí)也是網(wǎng)上提供最多的。
由于多個(gè)Activity要使用,關(guān)閉頁面的廣播最好寫在基類BaseActivity中,也可以在各個(gè)子頁面單獨(dú)寫,但是代碼量就增加了。

public class BaseActivity extends Activity {
    
    //根據(jù)需求定義自己需要關(guān)閉頁面的action
    public static final String RECEIVER_ACTION_FINISH_A = "receiver_action_finish_a";
    public static final String RECEIVER_ACTION_FINISH_B = "receiver_action_finish_b";
    public static final String RECEIVER_ACTION_FINISH_C = "receiver_action_finish_c";
    public static final String RECEIVER_ACTION_FINISH_D = "receiver_action_finish_d";
    
    private FinishActivityRecevier mRecevier;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mRecevier = new FinishActivityRecevier();
        registerFinishReciver();
    }

    private void registerFinishReciver() {
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(RECEIVER_ACTION_FINISH_A);
        intentFilter.addAction(RECEIVER_ACTION_FINISH_B);
        intentFilter.addAction(RECEIVER_ACTION_FINISH_C);
        intentFilter.addAction(RECEIVER_ACTION_FINISH_D);
        registerReceiver(mRecevier, intentFilter);
    }

    private class FinishActivityRecevier extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            //根據(jù)需求添加自己需要關(guān)閉頁面的action
            if (RECEIVER_ACTION_FINISH_A.equals(intent.getAction()) ||
                    RECEIVER_ACTION_FINISH_B.equals(intent.getAction()) ||
                    RECEIVER_ACTION_FINISH_C.equals(intent.getAction()) ||
                    RECEIVER_ACTION_FINISH_D.equals(intent.getAction())) {
                BaseActivity.this.finish();
            }
        }
    }

    @Override
    protected void onDestroy() {
        if (mRecevier != null) {
            unregisterReceiver(mRecevier);
        }
        super.onDestroy();
    }
}

發(fā)送廣播就需要在各個(gè)需求子Activity中進(jìn)行了,這里使用工具類,方便以后多次或者拓展使用,只需要在需求子Activity中直接調(diào)用就行。

public class BroadcastUtils {
    /**
     * 發(fā)送finish頁面的廣播
     * action可以自己根據(jù)需要添加
     * @param context
     */
    public static void sendFinishActivityBroadcast(Context context) {
        Intent intent = new Intent(BaseActivity.RECEIVER_ACTION_FINISH_B);
        context.sendBroadcast(intent);
        intent = new Intent(BaseActivity.RECEIVER_ACTION_FINISH_C);
        context.sendBroadcast(intent);
    }
}

優(yōu)劣:
有點(diǎn):最常規(guī)使用,不會出現(xiàn)內(nèi)存泄漏,在基類中操作,代碼量不多。
缺點(diǎn):項(xiàng)目中若是需要關(guān)閉頁面多的話,需要發(fā)送大量廣播,會降低性能。

方案二

直接static activity方式

這是網(wǎng)上提供的,代碼一看就明顯的內(nèi)存泄漏。但是。。。。。。

    private static AActivity sInstance;
    public static AActivity getInstance() {
        if (sInstance != null) {
            return sInstance;
        }
        return null;
    }
    public static void finishActivity() {
        if (sInstance != null) {
            sInstance.finish();
        }
    }

內(nèi)存泄漏明顯,之所以有但是,那是因?yàn)檫@種方式讓我想到加入弱引用WeakReference的方式。

public class BActivity extends BaseActivity {
    private static WeakReference<BActivity> sActivityRef;
    
    public static void finishActivity() {
        if (sActivityRef != null && sActivityRef.get() != null) {
            sActivityRef.get().finish();
        }
    }
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_b);
        sActivityRef = new WeakReference<>(this);
        Button btnB = (Button) findViewById(R.id.btn_b);
        btnB.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                startActivity(new Intent(BActivity.this, CActivity.class));
            }
        });
    }
    
}

糾結(jié)點(diǎn)在于,WeakReference被static之后,里面包裹的引用會被影響嗎?查了一下WeakReference以及JVM相關(guān),雖然WeakReference被static了,生命周期變長了,但是WeakReference關(guān)聯(lián)的對象不受影響的,依然遵循WeakReference在gc時(shí)候的規(guī)則。

優(yōu)劣:
優(yōu)點(diǎn):代碼簡單直觀,引入WeakReference,解決了內(nèi)存泄漏問題。
缺點(diǎn):在每個(gè)activity中都要添加,代碼量多。(不知是否可抽取到積累中,以后嘗試)

方案三

使用集合或者棧的方式

這種方式網(wǎng)上很多,但是。。。。。。

public class FinishActivityManager extends BaseActivity {
    private FinishActivityManager() {
    }
    private static FinishActivityManager sManager;
    private List<Activity> activityList;
    public static FinishActivityManager getManager() {
        if (sManager == null) {
            synchronized (FinishActivityManager.class) {
                if (sManager == null) {
                    sManager = new FinishActivityManager();
                }
            }
        }
        return sManager;
    }
    /**
     * 添加Activity到集合中
     */
    public void addActivity(Activity activity) {
        if (activityList == null) {
            activityList = new LinkedList<>();
        }
        activityList.add(activity);
    }
    /**
     * 關(guān)閉指定的Activity
     */
    public void finishActivity(Activity activity) {
        if (activityList != null && activity != null && activityList.contains(activity)) {
            //使用迭代器安全刪除
            for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) {
                Activity temp = it.next();
                // 清理掉已經(jīng)釋放的activity
                if (temp == null) {
                    it.remove();
                    continue;
                }
                if (temp == activity) {
                    it.remove();
                }
            }
            activity.finish();
        }
    }
    /**
     * 關(guān)閉指定類名的Activity
     */
    public void finishActivity(Class<?> cls) {
        if (activityList != null) {
            // 使用迭代器安全刪除
            for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) {
                Activity activity = it.next();
                // 清理掉已經(jīng)釋放的activity
                if (activity == null) {
                    it.remove();
                    continue;
                }
                if (activity.getClass().equals(cls)) {
                    it.remove();
                    activity.finish();
                }
            }
        }
    }
    /**
     * 關(guān)閉所有的Activity
     */
    public void finishAllActivity() {
        if (activityList != null) {
            for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) {
                Activity activity = it.next();
                if (activity != null) {
                    activity.finish();
                }
            }
            activityList.clear();
        }
    }
    /**
     * 退出應(yīng)用程序
     */
    public void exitApp() {
        try {
            finishAllActivity();
            // 退出JVM,釋放所占內(nèi)存資源,0表示正常退出
            System.exit(0);
            // 從系統(tǒng)中kill掉應(yīng)用程序
                android.os.Process.killProcess(android.os.Process.myPid());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

又有但是,這種方式注意在刪除的時(shí)候使用迭代器,否則會出現(xiàn)并發(fā)修改異常。
那就來說說但是,應(yīng)用中要是不使用這種封裝的方式去finish掉Activity的時(shí)候,封裝的manager并不知道,沒有斷開并釋放掉其引用,會引起內(nèi)存泄漏。所以WeakReference又要出場了,繼續(xù)修改吧。

public class FinishActivityManager extends BaseActivity {
    private FinishActivityManager() {
    }
    private static FinishActivityManager sManager;
    private Stack<WeakReference<Activity>> mActivityStack;
    public static FinishActivityManager getManager() {
        if (sManager == null) {
            synchronized (FinishActivityManager.class) {
                if (sManager == null) {
                    sManager = new FinishActivityManager();
                }
            }
        }
        return sManager;
    }
    /**
     * 添加Activity到棧
     * @param activity
     */
    public void addActivity(Activity activity) {
        if (mActivityStack == null) {
            mActivityStack = new Stack<>();
        }
        mActivityStack.add(new WeakReference<>(activity));
    }
    
    /**
     * 檢查弱引用是否釋放,若釋放,則從棧中清理掉該元素
     */
    public void checkWeakReference() {
        if (mActivityStack != null) {
            // 使用迭代器進(jìn)行安全刪除
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity temp = activityReference.get();
                if (temp == null) {
                    it.remove();
                }
            }
        }
    }
    /**
     * 獲取當(dāng)前Activity(棧中最后一個(gè)壓入的)
     * @return
     */
    public Activity currentActivity() {
        checkWeakReference();
        if (mActivityStack != null && !mActivityStack.isEmpty()) {
            return mActivityStack.lastElement().get();
        }
        return null;
    }
    /**
     * 關(guān)閉當(dāng)前Activity(棧中最后一個(gè)壓入的)
     */
    public void finishActivity() {
        Activity activity = currentActivity();
        if (activity != null) {
            finishActivity(activity);
        }
    }
    /**
     * 關(guān)閉指定的Activity
     * @param activity
     */
    public void finishActivity(Activity activity) {
        if (activity != null && mActivityStack != null) {
            // 使用迭代器進(jìn)行安全刪除
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity temp = activityReference.get();
                // 清理掉已經(jīng)釋放的activity
                if (temp == null) {
                    it.remove();
                    continue;
                }
                if (temp == activity) {
                    it.remove();
                }
            }
            activity.finish();
        }
    }
    /**
     * 關(guān)閉指定類名的所有Activity
     * @param cls
     */
    public void finishActivity(Class<?> cls) {
        if (mActivityStack != null) {
            // 使用迭代器進(jìn)行安全刪除
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity activity = activityReference.get();
                // 清理掉已經(jīng)釋放的activity
                if (activity == null) {
                    it.remove();
                    continue;
                }
                if (activity.getClass().equals(cls)) {
                    it.remove();
                    activity.finish();
                }
            }
        }
    }
    /**
     * 結(jié)束所有Activity
     */
    public void finishAllActivity() {
        if (mActivityStack != null) {
            for (WeakReference<Activity> activityReference : mActivityStack) {
                Activity activity = activityReference.get();
                if (activity != null) {
                    activity.finish();
                }
            }
            mActivityStack.clear();
        }
    }
    /**
     * 退出應(yīng)用程序
     */
    public void exitApp() {
        try {
            finishAllActivity();
            // 退出JVM,釋放所占內(nèi)存資源,0表示正常退出
            System.exit(0);
            // 從系統(tǒng)中kill掉應(yīng)用程序
            android.os.Process.killProcess(android.os.Process.myPid());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

代碼一目了然,之所以改成Stack,是因?yàn)橐7翧ctivity的任務(wù)棧的方式,關(guān)閉最后打開的Activity更加方便。
使用的話,在BaseActivity中onCreate()中addActivity,在onDestroy()中finishActivity(),其他功能在各個(gè)子Activity中根據(jù)需要添加。

優(yōu)劣:
優(yōu)點(diǎn):一勞永逸,一次封裝,方便后續(xù)使用。
缺點(diǎn):暫無。

方案四

使用Activity的launchMode

根據(jù)Android啟動(dòng)模式,standard和singleTop并不能實(shí)現(xiàn)項(xiàng)目需求,故排除。

singleTask和singleInstance在使用的時(shí)候會和onActivityResult()有點(diǎn)關(guān)系:
Android 5.0以上的版本能正常使用,沒有沖突;
Android 5.0以下的版本有個(gè)bug,在調(diào)用了startActivityForResult之后立馬就會調(diào)用onActivityResult,不會等到打開的Activity返回的時(shí)候才調(diào)用。
項(xiàng)目中很多Activity種都有startActivityForResult,故此種方式排除掉。

方案五

使用onActivityResult方式

根據(jù)方案四,此方式需要配合launchMode的standard和singleTop使用才能達(dá)到效果,所以局限性很大。

總結(jié)

以上就是幾種方案的對比,要是項(xiàng)目中需要關(guān)閉Activity不多,不需要發(fā)送大量廣播,可以使用方案一;方案二和方案三有異曲同工之處,首先推薦方案三。

能力有限,有不對之處,歡迎指出。

參考資料:
《深入理解Java虛擬機(jī):JVM高級特性與最佳實(shí)踐》
http://blog.csdn.net/weiwozhiyi/article/details/50791416
http://blog.csdn.net/lengguoxing/article/details/42145641
http://blog.csdn.net/u012815217/article/details/49280937

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容