preface

Recent projects involve the need to close another Activity within one Activity or to close multiple activities within one Activity, which does not involve exiting the application. Oneself first thought some program, also checked some program at the same time, each program compares the pros and cons.


Plan a

Way of broadcasting

This is the easiest one to think of, and one of the most available online. Since there are multiple activities to use, closing the broadcast page is best written in the base class BaseActivity or in individual child pages, but the amount of code increases.

public class BaseActivity extends Activity {

    // Define actions to close the page as required
    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(a); registerFinishReciver(); }private void registerFinishReciver() {
        IntentFilter intentFilter = new IntentFilter(a); 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) {
            // Add your own actions to close the page as required
            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(); }}Copy the code

Send broadcast needs to be carried out in each demand child Activity, here to use the tool class, convenient for future use or expansion, just need to call directly in the demand child Activity on the line.

public class BroadcastUtils {
    /** ** Send finish page broadcast * action can add * @param context */ as needed
    public static void sendFinishActivityBroadcast(Context context) {
        Intent intent = new Intent(BaseActivity.RECEIVER_ACTION_FINISH_B);
        context.sendBroadcast(intent);
        intent = newIntent(BaseActivity.RECEIVER_ACTION_FINISH_C); context.sendBroadcast(intent); }}Copy the code

Pros and cons: a bit: most common use, no memory leaks, operating in base classes, not much code. Disadvantages: If the project needs to close many pages, it needs to send a large number of broadcasts, which will reduce performance.

Scheme 2

Direct static activity mode

This is provided online, the code at first glance obvious memory leak. But…

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

The memory leak is obvious, the reason why there is but is because this way reminds me of the way to add WeakReference.

public class BActivity extends BaseActivity {
    private static WeakReference<BActivity> sActivityRef;

    public static void finishActivity(a) {
        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)); }}); }}Copy the code

The tricky point is, after the WeakReference is static, will the reference wrapped inside be affected? I checked WeakReference and related to JVM. Although WeakReference is static and its life cycle is longer, the objects associated with WeakReference are not affected and still follow the rules of WeakReference when GC.

Advantages and disadvantages: Advantages: The code is simple and intuitive, and WeakReference is introduced to solve the problem of memory leakage. Disadvantages: Add it in each activity and it has a lot of code. (I wonder if it can be extracted into the accumulation, try later)

Plan 3

Use collections or stacks

There’s a lot of this online, but…

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 = newFinishActivityManager(); }}}return sManager;
    }
    /** * Adds an Activity to the collection */
    public void addActivity(Activity activity) {
        if (activityList == null) {
            activityList = new LinkedList<>();
        }
        activityList.add(activity);
    }
    /** * Closes the specified Activity */
    public void finishActivity(Activity activity) {
        if(activityList ! =null&& activity ! =null && activityList.contains(activity)) {
            // Use iterators to safely delete
            for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) {
                Activity temp = it.next();
                // Clean up the activity that has been released
                if (temp == null) {
                    it.remove(a);continue;
                }
                if (temp == activity) {
                    it.remove();
                }
            }
            activity.finish();
        }
    }
    /** * Closes the Activity with the specified class name */
    public void finishActivity(Class
         cls) {
        if(activityList ! =null) {
            // Use iterators to safely delete
            for (Iterator<Activity> it = activityList.iterator(); it.hasNext(); ) {
                Activity activity = it.next();
                // Clean up the activity that has been released
                if (activity == null) {
                    it.remove(a);continue;
                }
                if (activity.getClass().equals(cls)) {
                    it.remove(a); activity.finish(); }}}}/** * Close all activities */
    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(); }}/** * exit the application */
    public void exitApp() {
        try {
            finishAllActivity();
            // Exit the JVM to release occupied memory resources. 0 indicates normal exit
            System.exit(0);
            // Kill the application from the system
                android.os.Process.killProcess(android.os.Process.myPid());
        } catch(Exception e) { e.printStackTrace(); }}}Copy the code

However, use iterators when deleting, otherwise concurrent modification exceptions will occur. However, if an application does not use this wrapper to finish an Activity, the wrapper manager does not know that it has broken and freed its reference, causing a memory leak. So WeakReference will come out again, continue to modify.

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 = newFinishActivityManager(); }}}return sManager;
    }
    /** * Add Activity to stack * @param Activity */
    public void addActivity(Activity activity) {
        if (mActivityStack == null) {
            mActivityStack = new Stack<>();
        }
        mActivityStack.add(new WeakReference<>(activity));
    }

    /** * checks if weak references are freed, and if so, clears the element */ from the stack
    public void checkWeakReference() {
        if(mActivityStack ! =null) {
            // Use iterators to safely delete
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity temp = activityReference.get(a);if (temp == null) {
                    it.remove(a); }}}}/** * gets the current Activity (the last one pushed in the stack) * @return */
    public Activity currentActivity() {
        checkWeakReference();
        if(mActivityStack ! =null && !mActivityStack.isEmpty()) {
            return mActivityStack.lastElement().get(a); }return null;
    }
    /** * Closes the current Activity (the last one pushed in the stack) */
    public void finishActivity() {
        Activity activity = currentActivity();
        if(activity ! =null) { finishActivity(activity); }}/** * Closes the specified Activity * @param Activity */
    public void finishActivity(Activity activity) {
        if(activity ! =null&& mActivityStack ! =null) {
            // Use iterators to safely delete
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity temp = activityReference.get(a);// Clean up the activity that has been released
                if (temp == null) {
                    it.remove(a);continue;
                }
                if (temp == activity) {
                    it.remove();
                }
            }
            activity.finish();
        }
    }
    /** * close all activities with the specified class name * @param CLS */
    public void finishActivity(Class
         cls) {
        if(mActivityStack ! =null) {
            // Use iterators to safely delete
            for (Iterator<WeakReference<Activity>> it = mActivityStack.iterator(); it.hasNext(); ) {
                WeakReference<Activity> activityReference = it.next();
                Activity activity = activityReference.get(a);// Clean up the activity that has been released
                if (activity == null) {
                    it.remove(a);continue;
                }
                if (activity.getClass().equals(cls)) {
                    it.remove(a); activity.finish(); }}}}/** * End all activities */
    public void finishAllActivity() {
        if(mActivityStack ! =null) {
            for (WeakReference<Activity> activityReference : mActivityStack) {
                Activity activity = activityReference.get(a);if(activity ! =null) { activity.finish(); } } mActivityStack.clear(); }}/** * exit the application */
    public void exitApp() {
        try {
            finishAllActivity();
            // Exit the JVM to release occupied memory resources. 0 indicates normal exit
            System.exit(0);
            // Kill the application from the system
            android.os.Process.killProcess(android.os.Process.myPid());
        } catch(Exception e) { e.printStackTrace(); }}}Copy the code

The code is clear at a glance. The reason for changing it to Stack is that it is more convenient to close the last opened Activity by imitating the way of Activity’s task Stack. When used, addActivity in BaseActivity onCreate(), finishActivity() in onDestroy(), and other functions can be added to each child Activity as needed.

Advantages and disadvantages: Advantages: once and for all, a package, convenient for subsequent use. Disadvantages: None at present.

Plan 4

Use the Activity’s launchMode

According to the Android startup mode, standard and singleTop cannot meet the requirements of the project, so they are excluded.

SingleTask and singleInstance are related to onActivityResult() when used: Android 5.0 + works without conflicts; Android versions below 5.0 have a bug that onActivityResult is called immediately after startActivityForResult is called, rather than waiting for the Activity to return. Many activities in the project have startActivityForResult, so this method is excluded.

Plan 5

Use onActivityResult

According to plan 4, this method needs to be used together with launchMode standard and singleTop to achieve the effect, so it has great limitations.

conclusion

The above is a comparison of several schemes. If the project needs to close a few activities and does not need to send a large number of broadcasts, you can use scheme 1. Plan 2 and Plan 3 have similarities, and plan 3 is recommended first.

Our capacity is limited, and we welcome you to point out any mistakes.

Resources: the deep understanding of the Java virtual machine: the JVM advanced features and best practices “blog.csdn.net/weiwozhiyi/… Blog.csdn.net/lengguoxing… Blog.csdn.net/u012815217/…