将对象从服务发送到活动(无法编组非 Parcelable)

Posted

技术标签:

【中文标题】将对象从服务发送到活动(无法编组非 Parcelable)【英文标题】:Send Object from Service to Activity (Can't marshal non-Parcelable) 【发布时间】:2011-09-29 14:11:32 【问题描述】:

我正在尝试将数据从我的活动发送到服务并接收一些信息,但我得到了:

java.lang.RuntimeException: 不能 编组非 Parcelable 对象 进程。

来自活动的代码如下所示:

Message msg = Message.obtain(null, 1);
    msg.obj=1;
    msg.replyTo=new Messenger(new PlanRequestIncomingHandler());
    try 
        msgService.send(msg);
     catch (RemoteException e) 
        Log.i(tag, "Can not send msg to service");
        e.printStackTrace();
    

当我设置 msg.obj = something 时,我得到 java.lang.RuntimeException,有人可以帮助我吗?

【问题讨论】:

【参考方案1】:

您可以通过 Messenger 传递 Parcelable 类型的对象。或者如果你想通过primitive data types 使用Bundle 包装器,如下所示。

服务结束:

//Create a bundle object and put your data in it
Bundle bundle = new Bundle();
bundle.putInt("key", 1);

Message msg = Message.obtain(null, 123);
msg.obj = bundle;
msg.replyTo = new Messenger(new PlanRequestIncomingHandler());
try 
    msgService.send(msg);
 catch (RemoteException e) 
    Log.i(tag, "Can't send msg to service");
    e.printStackTrace();

活动结束时:

switch(msg.what) 
    case 123:
        if(msg.obj != null) 
            Bundle bundle = (Bundle) msg.obj;
            System.out.println("Got integer "+ bundle.getInt("key"));
        
    break;

干杯:-)

【讨论】:

代码示例不完整!!! switch 写在哪里了?【参考方案2】:

老问题,但我正在回答,以便将来可能对某人有所帮助。

如果您使用的是实际对象,那么请务必实现 Parcelable android: How to implement Parcelable to my objects?

但是,正如 OP 所说,他尝试使用 Primitives 但它不起作用,这就是该做的。

问题出在这里msg.obj=1; 这需要一个实现 Parcelable 的实际对象

使用msg.arg1 = 1;

然后您可以使用 msg.arg1 在服务端检索参数

为简单起见,我使用(直接来自我的代码)

Message msg = Message.obtain(null, PlayerService.MSG_ACTION_SEEK, i, -1);

-1 对我来说只是一个持有者。

希望这会有所帮助。

编辑: 小心

Message msg = Message.obtain(null, PlayerService.MSG_ACTION_SEEK, i);

此签名等效于 OP 的第一次尝试,并且需要 Parcelable,这实际上是让我绊倒并让我首先搜索的原因。直到运行时才会抛出错误。

【讨论】:

【参考方案3】:

除了原始数据之外,您在活动和服务之间玩转的对象需要实现 Parcelable 并且最好是 Serializable。

希望对你有帮助,

最好的

-serkan

【讨论】:

我有 msg.obj=1 所以它的值是一个原始的并且它不起作用,我尝试了一个实现 Serializable 的自定义对象并且我得到了同样的错误。我认为@CommonsWare 是对的。我会尝试该解决方案并通知您... 当然,请随时通知我们,谢谢乔治,我很感激。【参考方案4】:

必须使用Bundle传递常规类型数据,否则会报错:

Java.lang.RuntimeException:不能跨编组进程使用非 Parcelable 对象。

因为Binder交易数据被称为Parcel,所以必须实现Parcelable接口,否则两个应用程序之间无法通信。之所以传递Bundle是因为该类实现了Parcelable接口。当然,如果要传递类还必须实现接口。

你可以这样写:

Message msg = Message.obtain(null, 1);
msg.getData().putInt("key",1);
msg.replyTo=new Messenger(new PlanRequestIncomingHandler());
try 
    msgService.send(msg);
 catch (RemoteException e) 
    Log.i(tag, "Can not send msg to service");
    e.printStackTrace();


对不起,我的英语很糟糕

【讨论】:

【参考方案5】:

我已经为 Android 实现了 Actor 模型(如 Akka),因为 Akka 需要 Java 8,所以我为 Android 做了自己的实现,使用 RxJava2,它很容易实现......一旦它在那里,你可以将持有任何对象的消息发送到任何接收者(Activity、Fragment、Service、Pojo 等),而无需担心线程或序列化

如果你不知道什么是Actor Model,我很难详细解释我自己的实现,但是如果你知道,你可以用一种方法制作一个名为“Actor”的接口

void onMessageReceived(Message message);

您可以通过您拥有的任何 Actor 实现此接口,并且要注册任何 Actor,您可以创建一个具有方法的 ActorSystem 类:

static void register(Actor actor, PublishSubject<Message>  mailbox); 
static void unregister(Actor actor);
static void send(Message message, Class<? extends Actor> ... actors);

当您注册您的 Actor(活动或服务)时,您可以通过以下方式决定接收消息的线程/调度程序:

PublishSubject.observeOn(Schedulers.trampoline());

然后你在 onCreate() 中注册你的 Actor 并在 onDestroy() 中取消注册

或者如果你想要一个库(但我没有测试它),你可以看看这个:

https://github.com/actorapp/droidkit-actors

【讨论】:

以上是关于将对象从服务发送到活动(无法编组非 Parcelable)的主要内容,如果未能解决你的问题,请参考以下文章

将意图从服务发送到活动

GCM 使用 content_available 向 iOS 推送通知(无法从非活动状态调用)

当应用程序从此活动关闭时,崩溃并显示错误 - “包裹:无法编组值...”

无法将图像从一个活动发送到另一个活动。请查看详情

Android 运行时错误:无法封送值

将包含其他自定义对象的对象列表从一个活动发送到另一个活动