Android的:异常通过意向发送ParcelFileDescriptor意向、异常、Android、ParcelFileDescriptor

2023-09-07 14:58:47 作者:你好美腻!

我写一个Android应用程序在我的服务需要发送图像到其他应用程序(通过广播消息或启动服务 - 那里可能有兴趣接收图像的多应用程序)。

I am writing an android app where my service needs to send an image to some other apps (via a broadcast message or by starting a service - there a multiple apps that might be interested to receive the image).

如果我加载图像转换为位图对象,并把它作为一个额外的意图,将实际工作的。不过,我想看看我是否可以发送ParcelFileDescrptor身边,而是和让客户端加载自己的位图对象(从阅读的规范,它看起来像ParcelFileDescriptor只是为此创建 - 进程之间共享文件)。在这里,我试图避免通过意向发送大对象。所以我写了这样的事情:

If I load the image into an Bitmap object and put it as an "Extra" of an Intent it would actually work. However, I want to see if I can send a ParcelFileDescrptor around instead, and let the client load the Bitmap object on their own (from reading the spec, it looks like ParcelFileDescriptor is created just for this purpose - sharing files between processes). Here I am trying to avoid sending large objects via Intent. So I wrote something like this:

    @Override
public int onStartCommand(Intent intent, int flags, int startId) {
    System.out.println("Service is called" + this.getClass());
    Intent newIntent = new Intent(MY_ACTION);
    try {
        File icon = new File(getExternalFilesDir(null), "robot_icon.jpg");
        icon.setReadable(true, false);
        if( !icon.exists() ) {
            System.out.println("Writting file " + icon);
                FileOutputStream out;
                out = new FileOutputStream(icon);
                BitmapFactory.decodeResource(getResources(), R.drawable.two_face_answer_map).compress(CompressFormat.JPEG, 100, out);
                out.close();
                System.out.println("Closing file after writing" + icon);
        }

        newIntent.putExtra(EXTRA_BITMAP, ParcelFileDescriptor.open(icon, ParcelFileDescriptor.MODE_READ_WRITE));
//          sendBroadcast(newIntent);
        startService(newIntent);
    } catch (FileNotFoundException e) {
        Log.e(TAG, "Error opening robot icon file", e);
    }catch (IOException e) {
        Log.e(TAG, "Error opening robot icon file", e);
    }

    System.out.println("No Exception");
    return super.onStartCommand(intent, flags, startId);
}

在执行此code,我总是收到一个RuntimeException,上面写着不许在这里写文件描述符。请注意,我看到的问题都与sendBroadcast以及startService选项。任何人都知道它为什么不在这里不允许?我做了什么错?难道我误解了ParcelFileDescriptor?下面是跟踪:

When this code is executed, I always receive a RuntimeException that said "Not allowed to write file descriptor here". Please note that I see the problem both with sendBroadcast as well as startService options. Anybody knows why it is not allowed here? What did I do wrong? Did I misunderstand the ParcelFileDescriptor? Here is the trace:

8月一号至一号:06:02.589:E / AndroidRuntime(7483):致命异常:主要 八月一日至1日:06:02.589:E / AndroidRuntime(7483):java.lang.RuntimeException的:无法启动服务com.test.robotsample.MyService@4161a0a8意图{CMP = com.test.robotsample / .MyService}: java.lang.RuntimeException的:不允许在这里写文件描述符 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2507) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.app.ActivityThread.access $ 1900年(ActivityThread.java:130) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.app.ActivityThread $ H.handleMessage(ActivityThread.java:1292) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.os.Handler.dispatchMessage(Handler.java:99) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.os.Looper.loop(Looper.java:137) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.app.ActivityThread.main(ActivityThread.java:4745) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在java.lang.reflect.Method.invokeNative(本机方法) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在java.lang.reflect.Method.invoke(Method.java:511) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:786) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在dalvik.system.NativeStart.main(本机方法) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):java.lang.RuntimeException的:产生的原因不允许在这里写文件描述符 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.os.Parcel.nativeWriteFileDescriptor(本机方法) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.os.Parcel.writeFileDescriptor(Parcel.java:552) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.os.ParcelFileDescriptor.writeToParcel(ParcelFileDescriptor.java:412) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.os.Parcel.writeParcelable(Parcel.java:1254) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.os.Parcel.writeValue(Parcel.java:1173) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.os.Parcel.writeMapInternal(Parcel.java:591) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.os.Bundle.writeToParcel(Bundle.java:1619) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.os.Parcel.writeBundle(Parcel.java:605) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.content.Intent.writeToParcel(Intent.java:6470) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.app.ActivityManagerProxy.startService(ActivityManagerNative.java:2468) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.app.ContextImpl.startService(ContextImpl.java:1149) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.content.ContextWrapper.startService(ContextWrapper.java:383) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在com.test.robotsample.MyService.onStartCommand(MyService.java:63) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):在android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2490) 八月一日至1日:06:02.589:E / AndroidRuntime(7483):10 ...更多

01-01 08:06:02.589: E/AndroidRuntime(7483): FATAL EXCEPTION: main 01-01 08:06:02.589: E/AndroidRuntime(7483): java.lang.RuntimeException: Unable to start service com.test.robotsample.MyService@4161a0a8 with Intent { cmp=com.test.robotsample/.MyService }: java.lang.RuntimeException: Not allowed to write file descriptors here 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2507) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.app.ActivityThread.access$1900(ActivityThread.java:130) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1292) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.os.Handler.dispatchMessage(Handler.java:99) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.os.Looper.loop(Looper.java:137) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.app.ActivityThread.main(ActivityThread.java:4745) 01-01 08:06:02.589: E/AndroidRuntime(7483): at java.lang.reflect.Method.invokeNative(Native Method) 01-01 08:06:02.589: E/AndroidRuntime(7483): at java.lang.reflect.Method.invoke(Method.java:511) 01-01 08:06:02.589: E/AndroidRuntime(7483): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 01-01 08:06:02.589: E/AndroidRuntime(7483): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 01-01 08:06:02.589: E/AndroidRuntime(7483): at dalvik.system.NativeStart.main(Native Method) 01-01 08:06:02.589: E/AndroidRuntime(7483): Caused by: java.lang.RuntimeException: Not allowed to write file descriptors here 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.os.Parcel.nativeWriteFileDescriptor(Native Method) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.os.Parcel.writeFileDescriptor(Parcel.java:552) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.os.ParcelFileDescriptor.writeToParcel(ParcelFileDescriptor.java:412) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.os.Parcel.writeParcelable(Parcel.java:1254) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.os.Parcel.writeValue(Parcel.java:1173) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.os.Parcel.writeMapInternal(Parcel.java:591) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.os.Bundle.writeToParcel(Bundle.java:1619) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.os.Parcel.writeBundle(Parcel.java:605) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.content.Intent.writeToParcel(Intent.java:6470) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.app.ActivityManagerProxy.startService(ActivityManagerNative.java:2468) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.app.ContextImpl.startService(ContextImpl.java:1149) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.content.ContextWrapper.startService(ContextWrapper.java:383) 01-01 08:06:02.589: E/AndroidRuntime(7483): at com.test.robotsample.MyService.onStartCommand(MyService.java:63) 01-01 08:06:02.589: E/AndroidRuntime(7483): at android.app.ActivityThread.handleServiceArgs(ActivityThread.java:2490) 01-01 08:06:02.589: E/AndroidRuntime(7483): ... 10 more

推荐答案

是的,这是不可能通过一个Intent来传递一个ParcelFileDescriptor。尽管这似乎并没有被明确记载在Android文档。

Yes, it is not possible to pass a ParcelFileDescriptor through an Intent. Although this does not seem to be clearly documented in the Android docs.

替代方案:

使用Bundle.putBinder()传递一个活页夹,将返回一个包裹的PFD(从API​​ 18)。 使用一个绑定服务,开始与Context.bindService(),在那里你又得到一个活页夹,通过它来获得PFD。