DP5 7.0 - 向挂起的意向添加额外内容是否失败



在跟踪器上添加链接的问题: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);
                }

我的 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); //.... }

奇怪的是,"提醒到火">仅在Android N设备上为空,但timeToFire是正确的。

我想这与包裹图书馆有关?我正在使用Java 1.8进行编译,并以Android API 24为目标。

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

如何正确将独特的附加内容传递给待处理的意图?

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

对于任何最终通过 AlarmManager 拔头发的人(并且还没有放弃并转到 JobScheduler(,生产 API 24 构建中的 Google 不支持将可包裹对象传递到 AlarmManager 中。

我解决这个问题的方法:如果需要将列表(或单个对象(发送到警报管理器中,请将该项目作为字符串存储到共享首选项中。(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;
}
}

设置适配器后,如果您使用的是某种 DI 框架(即 Dagger2(,则无需每次都使用 TypeAdapter 设置 GS0N,例如...

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

所以你所要做的就是运行。

/**
 * 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();
}

希望这有帮助。当然,当您需要从共享首选项中获取此对象时....

String json = sharedPrefs.getString(YOUR_KEY, "No object found");

执行典型的List对象= gson.fromJson(json,type(应该可以工作。

干杯。

我以前见过这种行为,使用自定义Parcelable对象和系统服务(例如,NotificationManager(。似乎发生的事情是系统尝试使用 PendingIntent ,并且由于某种原因,它试图取消Parcel Parcelable。这将失败,因为系统没有您的类。我已经有一段时间没有听说过有人遇到这种情况了,但完全有可能Android N中的回归重新引入了它。

您可以翻阅 LogCat,看看是否有来自系统(而不是您的应用程序(的任何消息(或者更好的是堆栈跟踪(似乎与您的警报事件有关。

如果您可以创建可重现的测试用例,请在 Android 问题跟踪器上提交问题。如果你想到它,请在此处发布一个链接,因为我想看一眼。

就解决方法而言,我可以想到两种:

  1. 不要把Parcelable放在那里。相反,请放置一个 ID,您可以根据需要使用该 ID 查找信息,无论是从内存中缓存(如果进程碰巧仍然存在(还是从持久性数据存储中的任何内容。

  2. Parcelable切换到我和其他人所说的"可捆绑",您可以在其中将对象转换为Bundle。基本上,只坚持操作系统定义的类,没有自定义类。然后,系统可以安全地Parcel Bundle(无论出于何种原因(。当然,这比简单地使用注释处理器来创建Parcelable实现要痛苦得多。

我发现将包裹包装在捆绑包中是有效的。

// When setting up the PendingIntent for the AlarmManager:
Intent intent = new Intent(context, MyService.class);
MyParcelable myParcelable = new MyParcelable();
Bundle b = new Bundle();
b.putParcelable(EXTRA_MY_PARCELABLE, myParcelable);
intent.putExtra(EXTRA_BUNDLE, b);
PendingIntent.getService(0, intent, 0);
// From the Service (or Activity, BroadcastReceiver, etc.):
Bundle b = intent.getExtra(EXTRA_BUNDLE);
MyParcelable myParcelable = b.getParcelableExtra(EXTRA_MY_PARCELABLE);

但是,我不确定这种方法是否面向未来。我已经在 android 错误跟踪器上评论了这个问题:https://code.google.com/p/android/issues/detail?id=209422#c11 但我怀疑它会收到回复,因为该问题已被标记为已关闭。

相关内容

  • 没有找到相关文章

最新更新