Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android 7 BroadcastReceiver onReceive intent.getExtras missing data

My app isn't working on Android 7. My BroadcastReceiver.onReceive method is called but the contents of the intent.getExtras is missing. I've verified that the data was correctly loaded. Here's a snippet from my onReceive method, where intent is passed as a parameter to onReceive.

Bundle bundle = intent.getExtras();
textMessage = bundle.getString("TEXT_MESSAGE");
ArrayList<MyPhoneNumber> phoneNumbersToText = bundle.getParcelableArrayList("PHONE_NUMBERS");

Both textMessage and phoneNumbersToText are null.

Here's a snippet from my manifest file:

<receiver android:process=":remote" android:name="com.friscosoftware.timelytextbase.AlarmReceiver"></receiver> 

Here's a snippet where the data is loaded:

Intent intent = new Intent(context , AlarmReceiver.class);  
intent.putExtra(Constants.TEXT_MESSAGE, scheduledItem.getMessageToSend());
intent.putExtra(Constants.PHONE_NUMBERS, scheduledItem.getPhoneNumbersToText());    

PendingIntent sender = PendingIntent.getBroadcast(context, getRequestCodeFromKey(key), intent, PendingIntent.FLAG_UPDATE_CURRENT);

// Get the AlarmManager service
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
alarmManager.set(AlarmManager.RTC_WAKEUP, selectedDateTime.getTimeInMillis(), sender);

The same code works fine in Android 6.

Any thoughts on what changes are required here for Android 7?

Thank you

like image 671
Phil O Avatar asked Aug 04 '16 18:08

Phil O


3 Answers

Android O version doesn't get extras properly in BroadcastReceivers. But the one great solution is to use an intent's setAction(String action) method to send the serializable Alarm object. Then get it back to object in onReceive. Here is the sample:

    Intent intent = new Intent(context, AlarmReceiver.class);
    intent.setAction(new Gson().toJson(alarm));

Then in your Alarm's receiver

public void onReceive(Context context, Intent intent) {

    String alarmSerializable = intent.getAction();
    if (alarmSerializable != null)
        alarm = new Gson().fromJson(alarmSerializable, Alarm.class);

    //TODO next, send notification
}

This is the common way for Android O and others.

like image 115
Taras Vovkovych Avatar answered Oct 16 '22 05:10

Taras Vovkovych


+1, it looks like you're having the same issue as me. I logged it on the tracker, (https://code.google.com/p/android/issues/detail?id=216581) which you commented on.

My solution was to use SharedPreferences to store my custom object. Then, when the alarmmanager fires, I run the following to get the object out. tl;dr, I use GSON to serialize/deserialize my custom POJO in/out of SharedPrefs as a String. For example:

 String json = getSharedPrefs(context).getString(NotificationUtility.NEXT_REMINDER_KEY, "No reminder found");
    try {
        Gson gson = new Gson();
        Reminder reminder = gson.fromJson(json, Reminder.class);
        if (reminder != null) {
            return reminder;
        }
    } catch (Exception error) {
        Log.i(TAG, "Error parsing json: " + error.getMessage(), error);
        return null;
    }
    return null;

Hope this helps you out!

like image 26
Aceofspadez44 Avatar answered Oct 16 '22 06:10

Aceofspadez44


I had a similar problem but I think I found an easy solution. Put your data inside a Bundle and send that Bundle with your alarm intent. In my case I wanted to send a serializable object with my intent.

Setup the alarm:

AlarmManager alarmManager = (AlarmManager)context.getSystemService(Context.ALARM_SERVICE);
`
Intent intent = new Intent(context, AlarmReciever.class);
Bundle bundle = new Bundle();

// creating an example object
ExampleClass exampleObject = new ExampleClass();

// put the object inside the Bundle
bundle.putSerializable("exapmle", exampleObject);

// put the Bundle inside the intent
intent.putExtra("bundle",bundle);

PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 1, intent, PendingIntent.FLAG_UPDATE_CURRENT);

// setup the alarm
alarmManager.setExact(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), alarmIntent);

Receive the alarm:

public class AlarmReciever extends BroadcastReceiver {

    @Override
    public void onReceive(Context context, Intent intent) {

        // get the Bundle
        Bundle bundle = intent.getBundleExtra("bundle");
        // get the object
        ExampleClass exampleObject = (ExampleClass)bundle.getSerializable("example");
    }

}

It worked fine for me. Hope it helps :)

like image 1
Martin the Martian Avatar answered Oct 16 '22 07:10

Martin the Martian