Android , broadcasting parcelable data

2019-03-26 07:54发布

问题:

I've implemented a class that extends NotificationListenerService which works fine for picking up on notifications posted.

I'm then wanting to take the statusBarNotification object received and broadcast it.

I'd doing the following:

@Override
public void onNotificationPosted(StatusBarNotification statusBarNotification) {

    Intent intent = new Intent();
    intent.putExtra("STATUS_BAR_NOTIFICATION",statusBarNotification);
    intent.setAction("com.example.NotificationPosted");
    sendBroadcast(intent);
}

But when I do this I get the following error:

01-05 01:50:14.333  19574-19673/com.example W/NotificationListenerService[NotificationListener]﹕ Error running onNotificationPosted
java.lang.RuntimeException: Not allowed to write file descriptors here
        at android.os.Parcel.nativeAppendFrom(Native Method)
        at android.os.Parcel.appendFrom(Parcel.java:431)
        at android.os.Bundle.writeToParcel(Bundle.java:1679)
        at android.os.Parcel.writeBundle(Parcel.java:636)
        at android.app.Notification.writeToParcel(Notification.java:962)
        at android.service.notification.StatusBarNotification.writeToParcel(StatusBarNotification.java:106)
        at android.os.Parcel.writeParcelable(Parcel.java:1285)
        at android.os.Parcel.writeValue(Parcel.java:1204)
        at android.os.Parcel.writeArrayMapInternal(Parcel.java:618)
        at android.os.Bundle.writeToParcel(Bundle.java:1692)
        at android.os.Parcel.writeBundle(Parcel.java:636)
        at android.content.Intent.writeToParcel(Intent.java:7013)
        at android.app.ActivityManagerProxy.broadcastIntent(ActivityManagerNative.java:2361)
        at android.app.ContextImpl.sendBroadcast(ContextImpl.java:1127)
        at android.content.ContextWrapper.sendBroadcast(ContextWrapper.java:365)
        at com.example.NotificationListener.onNotificationPosted(NotificationListener.java:113)
        at android.service.notification.NotificationListenerService$INotificationListenerWrapper.onNotificationPosted(NotificationListenerService.java:168)
        at android.service.notification.INotificationListener$Stub.onTransact(INotificationListener.java:56)
        at android.os.Binder.execTransact(Binder.java:404)
        at dalvik.system.NativeStart.run(Native Method)

Can anyone see what I'm doing wrong, or is this not possible. StatusBarNotification implements Parcelable

回答1:

I've had the same problem with notifications from Twitter. I successfully solved it setting the notification's extras to null.

Try this:

@Override
@SuppressLint("NewApi") // Notification.extras is only available in API Level 19+
public void onNotificationPosted(StatusBarNotification statusBarNotification) {

    // Apprarently, the bug is caused by the extras when they're written to the parcel
    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
         statusBarNotification.getNotification().extras = null;
    }
    Intent intent = new Intent();
    intent.putExtra("STATUS_BAR_NOTIFICATION",statusBarNotification);
    intent.setAction("com.example.NotificationPosted");
    sendBroadcast(intent);
}

Please note that this solution could break the functionality of notification's app if you send the contentIntent (the app could think the extras are there without checking).



回答2:

This is probably some kind of android bug as some users noted above. If you want to get around it and still use as much bundle as possible consider implementing custom bundle serializer/deserializer. I already answered a question how to build such thing in How to serialize a Bundle? and what is missing is how to actually use it when packing/unpacking the parcel. This is described here:

@Override public void writeToParcel(Parcel dest, int flags) {
    byte[] bytes = serializeBundle(yourBundle);
    dest.writeInt(bytes.length);
    dest.writeByteArray(bytes);
}

and then

    YourConstructor(Parcel in) {
         byte[] bytes = new byte[in.readInt()]; // read the length of the array
         in.readByteArray(bytes); // read bytes to array 
         yourBundle = deserializeBundle(bytes); // unpack the bundle
    }


回答3:

I have crash only kitkat(api 19). Му error(show all error scrooling to right):

Error running onNotificationPosted
                                                                                                                    java.lang.AbstractMethodError: abstract method not implemented
                                                                                                                          at android.service.notification.NotificationListenerService.onNotificationPosted(NotificationListenerService.java)
                                                                                                                          at service.CustomNotificationListenerService.onNotificationPosted(CustomNotificationListenerService.kt:46)
                                                                                                                          at android.service.notification.NotificationListenerService$INotificationListenerWrapper.onNotificationPosted(NotificationListenerService.java:168)
                                                                                                                          at android.service.notification.INotificationListener$Stub.onTransact(INotificationListener.java:56)
                                                                                                                          at android.os.Binder.execTransact(Binder.java:404)                                                                                                                     at dalvik.system.NativeStart.run(Native Method)

Simple Solve: i removed method: super()



回答4:

This solution worked for me:

@Override
public void onNotificationPosted(StatusBarNotification statusBarNotification) {

Bundle bundle = new Bundle(); statusBarNotification.getNotification().extras.putBundle("android.car.EXTENSIONS", bundle);

Intent intent = new Intent();
intent.putExtra("STATUS_BAR_NOTIFICATION",statusBarNotification);
intent.setAction("com.example.NotificationPosted");
sendBroadcast(intent);

}