WakefulBroadcastReceiver intent does not start only in some cases (weird)

I have a very strange error in my application. I am creating Alarm APP and I am using SQLite to store alarm data and broadcast receivers to manage alarm manager calls.

The onReceive code strangely doesn't behave the same in some cases. I am trying to start an Activity when the receiver receives a broadcast, almost 90% of the time everything goes well and I manage to start the Activity, but in some cases it is strange enough that the receiver executes the "startActivity (i)" statement but nothing happens.

It is very difficult to reproduce the BUG and during my debugging I found out what I mentioned, but more than that it is really difficult for me to understand how the call to startActivity () works in most cases and in some cases does not work. I searched the Stack community but nobody slept to have this kind of problem, everyone just had problems starting the activity because they didn't set the flag or because they didn't register the recipient in the manifest. Below I am posting the code.

public class AlarmReceiver extends WakefulBroadcastReceiver {
    // The app AlarmManager, which provides access to the system alarm services.
    private AlarmManager alarmMgr;
    // The pending intent that is triggered when the alarm fires.
    private PendingIntent alarmIntent;

    @Override
    public void onReceive(Context context, Intent intent) {
        Utils.logToFile("Received Alarm ,I am in onReceive(), ALARM ID: "+intent.getExtras().getInt(Constants.ALARM_ID));
        Intent intent = new Intent(context, StopAlarm.class);
        Bundle b = new Bundle();
        b.putInt(Constants.ALARM_ID, intent.getExtras().getInt(Constants.ALARM_ID));
        if(intent.getExtras().containsKey(Constants.SNOOZE_ALARM)){
            b.putString(Constants.SNOOZE_ALARM, intent.getExtras().getString(Constants.SNOOZE_ALARM));
        }
        i.putExtras(b);
        //this flag is needed to start an Activity from a BroadcastReceiver
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);


        //this method reads from the DB and sets the next alarm
        //I tried commenting this method so that no DB action is 
        //performed and still the bug happened
        setAlarm(context.getApplicationContext());
        //this method just logs data into a file that I have created to keep track of events 
        //since not always the device is connected with LogCat
        Utils.logToFile("Received Alarm, Intent(context, StopAlarm.class);");
    }

      

Do I need to set any other flag and how is it possible that startActivity (intent) behaves incorrectly in some cases?

EDIT

<activity
    android:label="@string/app_name"
    android:name="package.activity.StopAlarm"
    android:windowSoftInputMode="stateAlwaysHidden" 
    android:screenOrientation="sensorPortrait">
</activity>

<receiver android:name="package.receivers.AlarmReceiver" />

      

+3


source to share


2 answers


I finally solved the problem by creating an IntentService and starting with the IntentService and setting two flags on the Intent. After that, I put the code that reads from the DB in an activity launched from the IntentService. I tested the behavior almost 60 times and the application behaved correctly in all tests. I am posting the code below.

    public class MyAlarmReceiver extends WakefulBroadcastReceiver {
        // The app AlarmManager, which provides access to the system alarm services.
        private static AlarmManager alarmMgr;
        // The pending intent that is triggered when the alarm fires.
        private static PendingIntent alarmIntent;

        @Override
        public void onReceive(Context context, Intent intent) {
            Intent i = new Intent(context, AlarmIntentService.class);
            Bundle b = new Bundle();
            b.putInt(Constants.ALARM_ID, intent.getExtras().getInt(Constants.ALARM_ID));
            if(intent.getExtras().containsKey(Constants.SNOOZE_ALARM)){
                b.putString(Constants.SNOOZE_ALARM, intent.getExtras().getString(Constants.SNOOZE_ALARM));
            }
            i.putExtras(b);
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startWakefulService(context, i);
        }

      

This is the IntentService I need to implement



    public class AlarmIntentService extends IntentService {
        public AlarmIntentService() { 
            super("AlarmIntentService"); 
        } 

        @Override 
        protected void onHandleIntent(Intent intent) {
            Intent i = new Intent(this, StopAlarm.class);
            Bundle b = new Bundle();
            b.putInt(Constants.ALARM_ID, intent.getExtras().getInt(Constants.ALARM_ID));
            if(intent.getExtras().containsKey(Constants.SNOOZE_ALARM)){
                b.putString(Constants.SNOOZE_ALARM, intent.getExtras().getString(Constants.SNOOZE_ALARM));
            }
            i.putExtras(b);
            //THESE ARE THE FLAGS NEEDED TO START THE ACTIVITY AND TO PREVENT THE BUG
            //(CLEAR_TASK is crucial for the bug and new task is needed to start activity from outside of an activity)
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);

            startActivity(i);

            MyAlarmReceiver.completeWakefulIntent(intent);
        } 
    } 

      

This is the activity started by the IntentService. Here I have set the following alarm.

public class StopAlarm extends Activity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.stop_alarm);
        //this method reads from the DB and sets the next alarm
        MyAlarmReceiver.setAlarm(getApplicationContext());
        ...

      

+3


source


I had a similar problem. In my experience, the problem is that startActivity (i) is asynchronous. So in this case the program will simultaneously call the actions onCreate (), onStart (), etc., but also call QlokAlarmReceiver.completeWakefulIntent (intent) (without waiting for the activity to close), which will pop out the WakeLock. This may cause the device to sleep while the onCreate () or onStart () actions are being executed.

Ruby, I know my answer contradicts your solution, but my logs clearly indicated this order of events: - startActivity is called - onCreates an activity called - completeWakefulIntent (intent); callable between logs from onStart of activity



My workaround is to start the wakelock with a timeout of say 20 seconds before calling startActivity and then start another wakeLock on the onCreate activities to be released in the onDestroy method. I'm not sure if my solution is consistent with best practices, but I haven't found a better solution so far.

+1


source







All Articles