DP5 7.0 - 为待处理的意图添加额外功能会失败吗?

Ace*_*z44 8 android alarmmanager android-notifications parceler android-7.0-nougat

在跟踪器上添加关联问题:https://code.google.com/p/android/issues/detail? id = 216581 & thanks = 216581 & ts = 1468962325

所以我今天在我的Nexus 5X上安装了DP5 Android 7.0版本.我一直在开发一个应用程序,它使用Android的AlarmManager类在特定时间安排本地通知.在此版本发布之前,代码在运行KitKat,Lollipop和Marshmallow的设备上运行良好.

以下是我如何安排警报:

Intent intent = new Intent(context, AlarmManagerUtil.class);
            intent.setAction(AlarmManagerUtil.SET_NOTIFICATION_INTENT);
            intent.putExtra(AlarmManagerUtil.REMINDER_EXTRA, Parcels.wrap(reminders));
            intent.putExtra("time", when.getMillis());
            PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
            if (alarmManager != null) {
                if (Build.VERSION.SDK_INT >= 23) {
                  alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, when.getMillis(), pendingIntent);
                } else if (Build.VERSION.SDK_INT >= 19) {
                    alarmManager.setExact(AlarmManager.RTC_WAKEUP, when.getMillis(), pendingIntent);
                } else {
                    alarmManager.set(AlarmManager.RTC_WAKEUP, when.getMillis(), pendingIntent);
                }
Run Code Online (Sandbox Code Playgroud)

我的AlarmManagerUtil @onReceive的"SET_NOTIFICATION_INTENT"如下所示:

public void fireNotification(Context context, Intent intent) {
    List<Reminder> reminderToFire = Parcels.unwrap(intent.getParcelableExtra(REMINDER_EXTRA));
    long timeToFire = intent.getLongExtra("time", 0L); //.... }
Run Code Online (Sandbox Code Playgroud)

奇怪的是,"reminderToFire" 仅在Android N设备上为空,但timeToFire是正确的.

我在想它与Parceler图书馆有什么关系?我正在使用Java 1.8编译并针对Android API 24.

我肯定在网上寻找答案,但我的情况有点独特,因为代码100%适用于所有先前版本的Android(N预览下面的所有内容)...所以我遵循以下答案尽我所能:

如何才能正确地将唯一的附加内容传递给待处理的意图?

还有其他人有这个问题吗?

Ace*_*z44 8

对于任何人结束了在这里拉你的头发了AlarmManager(并没有放弃,并去的jobscheduler还),谷歌在生产API构建24不支持传递Parcelable对象到AlarmManager.

解决这个问题的方法:如果需要将一个List(或单个对象)发送到AlarmManager,请将该项目作为String存储到SharedPreferences中.(Gson.toJson(object,type))如果对象是一个接口,那里有许多接口适配器解决方案.一个我发现在S/O周围漂浮:

public final class InterfaceAdapter<T> implements JsonSerializer<T>, JsonDeserializer<T> {

public JsonElement serialize(T object, Type interfaceType, JsonSerializationContext context) {
    final JsonObject wrapper = new JsonObject();
    wrapper.addProperty("type", object.getClass().getName());
    wrapper.add("data", context.serialize(object));
    return wrapper;
}

public T deserialize(JsonElement elem, Type interfaceType, JsonDeserializationContext context) throws JsonParseException {
    final JsonObject wrapper = (JsonObject) elem;
    final JsonElement typeName = get(wrapper, "type");
    final JsonElement data = get(wrapper, "data");
    final Type actualType = typeForName(typeName);
    return context.deserialize(data, actualType);
}

private Type typeForName(final JsonElement typeElem) {
    try {
        return Class.forName(typeElem.getAsString());
    } catch (ClassNotFoundException e) {
        throw new JsonParseException(e);
    }
}

private JsonElement get(final JsonObject wrapper, String memberName) {
    final JsonElement elem = wrapper.get(memberName);
    if (elem == null)
        throw new JsonParseException("no '" + memberName + "' member found in what was expected to be an interface wrapper");
    return elem;
}
}
Run Code Online (Sandbox Code Playgroud)

一旦你设置了适配器,如果你正在使用某种DI框架(即Dagger2),你就不需要每次使用TypeAdapter设置GS0N ......

@Singleton
@Provides
public Gson providesGson() {
    return new GsonBuilder()
            .registerTypeAdapter(YourInterfaceClass.class, new InterfaceAdapter<YourInterfaceClass>())
            .create();
Run Code Online (Sandbox Code Playgroud)

所以你要做的就是跑......

/**
 * stores yourInterfaceClass in shared prefs
 */
public void setNextReminder(List<YourInterfaceClass> yourInterfaceClass) {
    Type type = new TypeToken<List<YourInterfaceClass>>() {}.getType();
    sharedPrefs.edit().putString(YOUR_KEY, gson.toJson(yourInterfaceClass, type)).apply();
}
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.当然,当你需要从共享的prefs中获取这个对象....

String json = sharedPrefs.getString(YOUR_KEY, "No object found");
Run Code Online (Sandbox Code Playgroud)

做典型的List object = gson.fromJson(json,type)应该可行.

干杯.

  • 我认为您不需要通过共享首选项传递.实际上基类型仍在工作,你可以通过意图传递json字符串,并在接收时用Gson解析它.另外我注意到传递Bitmap没有麻烦...(实现了Parcelable) (2认同)