The Android timer repeatedly starts the Activity problem (actually it is the pit that sends the broadcast)

Project scenario:

During the project development two days ago, in case of such a scenario, a time clock function needs to be done. After the time clock is turned on, an Activity pops up after the specified time (relative time) arrives.

Problem Description:

The above scenario is not difficult to implement. You can send a broadcast by turning on the time clock function, define a Handler timer in the broadcast receiver, and start the Activity when the specified time arrives. However, I found that there are two activities that pop up when the specified time arrives. Even if I set this Ac to singleTop startup mode, it still can't be solved, which shows that the two Ac instances started are not in the same stack.
After thinking hard, I consulted my predecessors.

Cause analysis:

Our project has a MainActivity. My module is SettingActivity. They also inherit BaseActivity in the project architecture. When I send a broadcast, I call the attribute activity of the parent class of Fragment (inherited from BaseFragment), as shown in the figure

And enter the activity to see

It can be found that the ac is transformed upward into BaseActivity. What problems will be caused by sending broadcasts with this ac instance?
When we enter the project, we start MainActivity first, and MainActivity is also a subclass of BaseActivity. When we send a broadcast, the ac used is also of BaseActivity type. As a result, Java will use all instances of BaseActivity type to send a broadcast. Therefore, the reason why the timer logic code is executed twice is that MainActivity is passed in once, SettingActivity was passed in once.

The logic in the broadcast receiver is not important in this example, but let's take a look:

private int intervalTime = KVUtils.getInstance().getInt(Setting.INTERVAL_TIME, 60);

private Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            switch (msg.what){
                case 0:
                    if (intervalTime == 0 ){
                        //stopTimeClock();
                        Intent startIntent = new Intent(mContext, TimeClockActivity.class);
                        mContext.startActivity(startIntent);
                        LogUtils.d("TimeClockActivity Start in broadcast receiver");
                        intervalTime = KVUtils.getInstance().getInt(Setting.INTERVAL_TIME, 60);
                    } else {
                        String i = ""+ intervalTime;
                        LogUtils.d(i);
                        intervalTime--;
                        sendEmptyMessageDelayed(0,1000);
                    }
                    break;
                default:
                    break;
            }
        }
    };
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Setting.TIME_CLOCK_ACTION)) {
            this.mContext = context;

            startTimeClock();
        }
    }
    private void startTimeClock() {
        //Judge non empty processing to prevent duplicate creation
        //stopTimeClock();
        Message msg = new Message();
        msg.what = 0;
        handler.sendMessage(msg);
    }

onReceive() starts the Handler for timing operation by judging whether the broadcast action meets the conditions. The intervalTime parameter is reduced by one second until its value is 0.

Solution:

Since there are two activities to start the Handler (MainActivity and SettingActivity, we want only SettingActivity), we can judge whether the current incoming context or Activity is SettingActivity before sending the Handler information. Modify the code in onReceive:

@Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals(Setting.TIME_CLOCK_ACTION) && context instanceof SettingActivity) {
            this.mContext = context;

            startTimeClock();
        }
    }

That is, add a necessary condition to the if statement, that is, send messages to the handler only when the context is SettingActivity instance, so that the MainActivity instance will not send messages and the logic in the handler will not be executed repeatedly!

Keywords: Java Android

Added by FatStratCat on Mon, 20 Dec 2021 11:17:57 +0200