Pendingintent getbroadcast丢失了可分配的数据

BIN*_*BIN 4 android broadcast parcelable android-intent android-pendingintent

这是问题所在.我的程序在Android 6.0中运行完美.将设备更新到android 7.0后.Pendingintent无法将可分配的数据传递给boradcast reveiver.这是代码.

发出警报

public static void setAlarm(@NonNull Context context, @NonNull Todo todo) {
    AlarmManager alarmManager = (AlarmManager) context.getSystemService(context.ALARM_SERVICE);
    Intent intent = new Intent(context, AlarmReceiver.class);
    intent.putExtra("KEY_TODO", todo);
    PendingIntent alarmIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
    alarmManager.set(AlarmManager.RTC_WAKEUP, todo.remindDate.getTime(), alarmIntent);
}
Run Code Online (Sandbox Code Playgroud)

Todo是一个Parcelable类,而todo是我在通知中需要的实例.

在Broadcastreceiver中,我无法获取可用的数据.

public void onReceive(Context context, Intent intent) {

    Todo todo = intent.getParcelableExtra("KEY_TODO");

}
Run Code Online (Sandbox Code Playgroud)

这是我在这里调试输入图像描述时的意图 结果

我不知道为什么意图只包含一个我从未放入的Integer.Carcelable todo在哪里.此代码在Android 6.0中没有问题,但无法在7.0中运行

Com*_*are 17

引用自己:

自定义Parcelable类 - 您的应用程序独有的,而不是Android框架的一部分 - 多年来作为Intent额外内容时出现了间歇性问题.基本上,如果核心OS过程需要修改Intent附加内容,那么该过程最终会尝试重新创建Parcelable对象,作为设置Bundle修改附加内容的一部分.该进程没有您的类,因此它获得运行时异常.

可能发生这种情况的一个领域是AlarmManager.使用可能适用于旧版Android的自定义Parcelable对象的代码在Android N上无效.AlarmManager

最有效的解决方法,我知道的是手动的转换Parceable自己变成一个byte[]和放进了Intent额外的手动转换回一个Parcelable需要.此Stack Overflow答案 显示了该技术,此示例项目提供了完整的工作示例.

关键位是之间的转换Parcelablebyte[]:

/***
 Copyright (c) 2016 CommonsWare, LLC
 Licensed under the Apache License, Version 2.0 (the "License"); you may not
 use this file except in compliance with the License. You may obtain a copy
 of the License at http://www.apache.org/licenses/LICENSE-2.0. Unless required
 by applicable law or agreed to in writing, software distributed under the
 License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
 OF ANY KIND, either express or implied. See the License for the specific
 language governing permissions and limitations under the License.

 From _The Busy Coder's Guide to Android Development_
 https://commonsware.com/Android
 */

package com.commonsware.android.parcelable.marshall;

import android.os.Parcel;
import android.os.Parcelable;

// inspired by https://stackoverflow.com/a/18000094/115145

public class Parcelables {
  public static byte[] toByteArray(Parcelable parcelable) {
    Parcel parcel=Parcel.obtain();

    parcelable.writeToParcel(parcel, 0);

    byte[] result=parcel.marshall();

    parcel.recycle();

    return(result);
  }

  public static <T> T toParcelable(byte[] bytes,
                                   Parcelable.Creator<T> creator) {
    Parcel parcel=Parcel.obtain();

    parcel.unmarshall(bytes, 0, bytes.length);
    parcel.setDataPosition(0);

    T result=creator.createFromParcel(parcel);

    parcel.recycle();

    return(result);
  }
}
Run Code Online (Sandbox Code Playgroud)


Nju*_*ert 15

根据问题下方评论中@David Wasser 的建议,我能够解决相同的问题,如下所示:

    public static void setAlarm(@NonNull Context context, @NonNull Todo todo) {

      ...

      Intent intent = new Intent(context, AlarmReceiver.class);

      Bundle todoBundle = new Bundle();
      todoBundle.putParcelable("KEY_TODO", todo);

      intent.putExtra("KEY_TODO", todoBundle); // i just reuse the same key for convenience

      ...

    }
Run Code Online (Sandbox Code Playgroud)

然后在广播接收器中像这样提取包:

    public void onReceive(Context context, Intent intent) {

        Bundle todoBundle = intent.getBundleExtra("KEY_TODO");

        Todo todo;

        if (todoBundle != null ) {
            todo = todoBundle.getParcelable("KEY_TODO");
        }

    }
Run Code Online (Sandbox Code Playgroud)