首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >安卓ResultReceiver跨软件包

安卓ResultReceiver跨软件包
EN

Stack Overflow用户
提问于 2011-04-21 19:33:51
回答 3查看 7.6K关注 0票数 13

我在包A (SignerClient)中有一个活动,在包B (MyService)中有一个服务。

活动的结果接收者:

代码语言:javascript
复制
private ResultReceiver resultreceiver = new ResultReceiver(null) {
            @Override
            protected void onReceiveResult(int resultCode, Bundle resultData) {
            ...
            }
        };

启动服务:

代码语言:javascript
复制
Intent intent = new Intent("com.example.STARTSERVICE");
intent.putExtra("resultreceiver", resultreceiver);            
startService(intent);

接收端:

代码语言:javascript
复制
 ResultReceiver rr = (ResultReceiver) intent.getParcelableExtra("resultreceiver");

当客户端和服务器在同一个包中时,这样做可以很好地工作。但在这种情况下,我得到:

代码语言:javascript
复制
FATAL EXCEPTION: IntentService[MyService]
android.os.BadParcelableException: ClassNotFoundException when unmarshalling: com.example.cryptoclient.SignerClient$1
at android.os.Parcel.readParcelable(Parcel.java:1883)
at android.os.Parcel.readValue(Parcel.java:1771)
at android.os.Parcel.readMapInternal(Parcel.java:2008)
at android.os.Bundle.unparcel(Bundle.java:208)
at android.os.Bundle.getParcelable(Bundle.java:1100)
at android.content.Intent.getParcelableExtra(Intent.java:3396)
at org.axades.service.MyService.onHandleIntent(MyService.java:28)
at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:59)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:123)
at android.os.HandlerThread.run(HandlerThread.java:60)

我遗漏了什么?我的想法有可能实现吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2011-08-15 21:46:16

是的,你的想法是可能的。抛出ClassNotFoundException异常是因为您试图对由不同ClassLoader在不同进程中创建的类进行解包。

ResultReceiver类实现了适用于进程间调用(IPC)的Parcelable接口,然而,要读取服务中的对象,您需要使用与在客户端应用程序中(即在活动中)创建对象时使用的相同ClassLoader。要在服务端获得该ClassLoader,请调用createPackageContext方法,传递客户机包名称和CONTEXT_INCLUDE_CODE|CONTEXT_IGNORE_SECURITY标志组合。这将返回客户端上下文对象,从中可以获得正确的ClassLoader对象。

示例:

代码语言:javascript
复制
public int onStartCommand(Intent intent, int flags, int startId) {
  try {

// assuming SignerClient activity is located in the package "com.example.client.A"
    Context context = createPackageContext("com.example.client.A", Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
    ClassLoader cl = context.getClassLoader();

    Bundle bundle = intent.getExtras();
    bundle.setClassLoader(cl);
    ResultReceiver rr = bundle.getParcelable("resultreceiver");

//... your interaction with ResultReceiver ...
    rr.send(1, null);   // will result in a onReceiveResult call in the client activity

  } catch (NameNotFoundException e) {
    Log.e("MyService", "SignerClient package context was not found", e);
    throw new RuntimeException(e);
  }
  return START_STICKY;
}

我只是在我的代码中使用了它-效果很好。

更新

但是,我建议考虑使用Messenger而不是ResultReceiver。它实现了Parcelable接口,并且不需要扩展,因此ClassLoader问题是不可能的。它也是recommended in the official documentation

更新2

如果您仍然更喜欢使用ResultReceiver,请查看Robert's answer in this thread。它看起来比繁琐的上下文操作更干净、更简单。

票数 15
EN

Stack Overflow用户

发布于 2012-08-30 01:04:26

我想跨包使用ResultReceiver,而不得不加载另一个包的上下文对我来说似乎并不合适……毕竟,接收包不需要知道所使用的ResultReceiver的特定子类,它只需要能够调用send()并让IPC绑定器魔术发生。需要让特定的子类可用似乎是一个设计缺陷。

有一种解决方法:

代码语言:javascript
复制
public static ResultReceiver receiverForSending(ResultReceiver actualReceiver) {
    Parcel parcel = Parcel.obtain();
    actualReceiver.writeToParcel(parcel,0);
    parcel.setDataPosition(0);
    ResultReceiver receiverForSending = ResultReceiver.CREATOR.createFromParcel(parcel);
    parcel.recycle();
    return receiverForSending;
}

这段代码将ResultReceiver的某个子类的实例转换为ResultReceiver本身的实例,但它仍然会将结果发送到原始的actualReceiverreceiverForSending可以在Intent中额外发送到另一个包,并且可以很好地解组。

票数 29
EN

Stack Overflow用户

发布于 2016-09-07 23:46:32

由于某些原因,我只在android.support.v4.os.ResultReceiver上遇到了这个错误。将导入更改为android.os.ResultReceiver使ipc结果立即生效。不需要解决方法!

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5743485

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档