Android--關閉某個指定activity

最近項目中有這樣的需要,在關閉當前Activity同時關閉前面兩個Activity,不涉及到應用的退出。自己想了一些方案,也查了一些資料,做個筆記吧。

方案一

廣播的方式

這個是最容易想到的,同時也是網上提供最多的。 由於多個Activity要使用,關閉頁面的廣播最好寫在基類BaseActivity中,也可以在各個子頁面單獨寫,但是代碼量就增加了。

public class BaseActivity extends Activity {
//根據需求定義自己需要關閉頁面的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) {
//根據需求添加自己需要關閉頁面的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();
}
}

發送廣播就需要在各個需求子Activity中進行了,這裡使用工具類,方便以後多次或者拓展使用,只需要在需求子Activity中直接調用就行。

public class BroadcastUtils {
/**
* 發送finish頁面的廣播
* action可以自己根據需要添加
* @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);
}
}

優劣:

優點:最常規使用,不會出現內存洩漏,在基類中操作,代碼量不多。

缺點:項目中若是需要關閉頁面多的話,需要發送大量廣播,會降低性能。

方案二

直接static activity方式

這是網上提供的,代碼一看就明顯的內存洩漏。但是。。。。。。

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

內存洩漏明顯,之所以有但是,那是因為這種方式讓我想到加入弱引用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));
}
});
}
}
/<bactivity>

WeakReference以及JVM相關,雖然WeakReference被static了,生命週期變長了,但是WeakReference關聯的對象不受影響的,依然遵循WeakReference在gc時候的規則。

優劣: 優點:代碼簡單直觀,引入WeakReference,解決了內存洩漏問題。 缺點:在每個activity中都要添加,代碼量多。(不知是否可抽取到基類中,以後嘗試)

方案三

使用集合或者棧的方式

public class FinishActivityManager {
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);
}
/**
* 關閉指定的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();
// 清理掉已經釋放的activity
if (temp == null) {
it.remove();
continue;
}
if (temp == activity) {
it.remove();
}
}
activity.finish();
}
}
/**
* 關閉指定類名的Activity
*/
public void finishActivity(Class> cls) {
if (activityList != null) {
// 使用迭代器安全刪除
for (Iterator<activity> it = activityList.iterator(); it.hasNext(); ) {
Activity activity = it.next();
// 清理掉已經釋放的activity
if (activity == null) {
it.remove();
continue;
}
if (activity.getClass().equals(cls)) {
it.remove();
activity.finish();

}
}
}
}
/**
* 關閉所有的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();
}
}
/**
* 退出應用程序
*/
public void exitApp() {
try {
finishAllActivity();
// 退出JVM,釋放所佔內存資源,0表示正常退出
System.exit(0);
// 從系統中kill掉應用程序
android.os.Process.killProcess(android.os.Process.myPid());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/<activity>/<activity>/<activity>/<activity>

這種方式注意在刪除的時候使用迭代器,否則會出現併發修改異常。 那就來說說但是,應用中要是不使用這種封裝的方式去finish掉Activity的時候,封裝的manager並不知道,沒有斷開並釋放掉其引用,會引起內存洩漏。所以WeakReference又要出場了。

public class FinishActivityManager {
private FinishActivityManager() {
}
private static FinishActivityManager sManager;
private Stack<weakreference>> 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) {
// 使用迭代器進行安全刪除
for (Iterator<weakreference>> it = mActivityStack.iterator(); it.hasNext(); ) {
WeakReference<activity> activityReference = it.next();
Activity temp = activityReference.get();
if (temp == null) {
it.remove();
}
}
}
}
/**
* 獲取當前Activity(棧中最後一個壓入的)
* @return
*/
public Activity currentActivity() {

checkWeakReference();
if (mActivityStack != null && !mActivityStack.isEmpty()) {
return mActivityStack.lastElement().get();
}
return null;
}
/**
* 關閉當前Activity(棧中最後一個壓入的)
*/
public void finishActivity() {
Activity activity = currentActivity();
if (activity != null) {
finishActivity(activity);
}
}
/**
* 關閉指定的Activity
* @param activity
*/
public void finishActivity(Activity activity) {
if (activity != null && mActivityStack != null) {
// 使用迭代器進行安全刪除
for (Iterator<weakreference>> it = mActivityStack.iterator(); it.hasNext(); ) {
WeakReference<activity> activityReference = it.next();
Activity temp = activityReference.get();
// 清理掉已經釋放的activity
if (temp == null) {
it.remove();
continue;
}
if (temp == activity) {
it.remove();
}
}
activity.finish();
}
}
/**
* 關閉指定類名的所有Activity
* @param cls
*/
public void finishActivity(Class> cls) {
if (mActivityStack != null) {
// 使用迭代器進行安全刪除
for (Iterator<weakreference>> it = mActivityStack.iterator(); it.hasNext(); ) {

WeakReference<activity> activityReference = it.next();
Activity activity = activityReference.get();
// 清理掉已經釋放的activity
if (activity == null) {
it.remove();
continue;
}
if (activity.getClass().equals(cls)) {
it.remove();
activity.finish();
}
}
}
}
/**
* 結束所有Activity
*/
public void finishAllActivity() {
if (mActivityStack != null) {
for (WeakReference<activity> activityReference : mActivityStack) {
Activity activity = activityReference.get();
if (activity != null) {
activity.finish();
}
}
mActivityStack.clear();
}
}
/**
* 退出應用程序
*/
public void exitApp() {
try {
finishAllActivity();
// 退出JVM,釋放所佔內存資源,0表示正常退出
System.exit(0);
// 從系統中kill掉應用程序
android.os.Process.killProcess(android.os.Process.myPid());
} catch (Exception e) {
e.printStackTrace();
}
}
}
/<activity>/<activity>/<weakreference>/<activity>/<weakreference>/<activity>/<weakreference>/<weakreference>

代碼一目瞭然,之所以改成Stack,是因為要模仿Activity的任務棧的方式,關閉最後打開的Activity更加方便。 使用的話,在BaseActivity中onCreate()中addActivity,在onDestroy()中finishActivity(),其他功能在各個子Activity中根據需要添加。

優劣:

優點:一勞永逸,一次封裝,方便後續使用。

缺點:暫無。

方案四

使用Activity的launchMode

根據Android啟動模式,standard和singleTop並不能實現項目需求,故排除。

singleTask和singleInstance在使用的時候會和onActivityResult()有點關係: Android 5.0以上的版本能正常使用,沒有衝突; Android 5.0以下的版本有個bug,在調用了startActivityForResult之後立馬就會調用onActivityResult,不會等到打開的Activity返回的時候才調用。 項目中很多Activity種都有startActivityForResult,故此種方式排除掉。

方案五

使用onActivityResult方式

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

方案六

使用Rxbus

Rxbus也是可以實現的,根據自己的需求來決定吧

要是項目中需要關閉Activity不多,不需要發送大量廣播,可以使用方案一;方案二和方案三有異曲同工之處,首先推薦方案三;比較之下我在項目中用了方案三。

【附】相關架構及資料

領取獲取往期Android高級架構資料、源碼、筆記、視頻。高級UI、性能優化、架構師課程、NDK、混合式開發(ReactNative+Weex)微信小程序、Flutter全方面的Android進階實踐技術

Android--關閉某個指定activity

Android高級技術大綱

領取方式:

關注+私信回覆“安卓資料”免費獲取!


分享到:


相關文章: