Android:IOException read fail:EBADF (Bad file descriptor)

Deadly 提交于 2020-12-10 04:27:27

写这篇博客主要想记录一下这个问题,我觉得大家应该都不会碰到。

在我之前的一篇文章Android Q:上传图片java.io.FileNotFoundException: open failed: EACCES (Permission denied) 中有说到,新安卓版本下,使用公共文件资源不能够File file = new File(path)了,需要使用FD,也就是FileDescriptor。现在,我这边碰到了一个非常非常奇葩的问题,就如标题所示:

IOException read fail:EBADF (Bad file descriptor)

这个错误,是try-catch出来,然后Toast到屏幕上,截图下来的。是不是这套操作,很奇怪,为什么我不debug?

这个错误,在debug环境下的安装包,是不会报错的,在release安装包下,会报错。在测试机上会报错,在我手机findx上不报错。在上一个项目中用到,没报过这个错误,在这个项目后期,碰到了这个错误。

非常奇葩,根本想不通,为什么同一套代码,连接口地址都一样,release包就报错了。

我把功能代码整合了一下,放上来

//现在假定,已经获取到了一个资源的Uri 并且要上传

private void update() throws IOException {
    ParcelFileDescriptor parcelFileDescriptor = getApplication.getContentResolver().openFileDescriptor(uri, "r");
        
    FileDescriptor fileDescriptor = parcelFileDescriptor.getFileDescriptor();
    FileInputStream fis = new FileInputStream(fileDescriptor);
    ByteArrayOutputStream swapStream = new ByteArrayOutputStream();
    byte[] buff = new byte[1024*4]; //buff用于存放循环读取的临时数据
    int rc = 0;
    while ((rc = fis.read(buff, 0, 100)) > 0) {
       swapStream.write(buff, 0, rc);
    }
    MultipartBody.Builder builder = new MultipartBody.Builder()
                .setType(MultipartBody.FORM);//表单类型
        RequestBody body = RequestBody.create(MediaType.parse("multipart/form-data"), swapStream.toByteArray());//表单类型

        builder.addFormDataPart("file", "xxx.mp4", body);
    Retrofit.getApi.update(builder.build().parts())
            .compose(做一些切换线程的操作,和数据处理)
            .subscribe(new Observe{
            //成功 失败回调
    });
}

我那边分好几个文件调用,但是整套流程大致就是这样,获取文件byte[],构建formData文件Retrofit上传,调用接口。

调用的时候,你就需要try-catch,然后release环境下,我这边就报错了。

直接说解决办法吧,因为我也不知道为什么会报错,有知道的大佬可以提点一下我,由于我用的MVVM框架,而ViewModel中是不能持有activity的context的,但是可以有application,因此在使用getContentResolver(),我用的是application。当时我是把这代码放在了MainActivity中测试,发现居然不报错,成功上传了,对比下,只有在获取getContentResolver()这个时候不一样。

我把所有getContentResolver的地方都使用了activity的context,就没有报这个错误了。就是代码结构变化比较大,需要把获取ParcelFileDescriptor放在View模块执行,然后再到ViewModel中转化成byte[]。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!