如何将 ResponseBody(在我的情况下为 PDF)写入外部存储? java.lang.IllegalStateException 的问题:已关闭

Posted

技术标签:

【中文标题】如何将 ResponseBody(在我的情况下为 PDF)写入外部存储? java.lang.IllegalStateException 的问题:已关闭【英文标题】:How to write ResponseBody (in my case PDF) to external storage? Problem with java.lang.IllegalStateException: closed 【发布时间】:2021-12-28 06:47:27 【问题描述】:

我想将 ResponseBody 写入外部存储(下载文件夹)。直到一周前,一切正常,然后我需要更新 okhttp3 版本,现在当我运行我的应用程序时,发生了以下情况之一:

这是我的改造:

HttpLoggingInterceptor logging = new HttpLoggingInterceptor();
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);
    OkHttpClient client = new OkHttpClient.Builder()
            .addInterceptor(logging)
            .connectTimeout(2, TimeUnit.MINUTES)
            .writeTimeout(2, TimeUnit.MINUTES)
            .readTimeout(2, TimeUnit.MINUTES)
            .build();


    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(link)
            .addConverterFactory(ScalarsConverterFactory.create())
            .addConverterFactory(create())
            .client(client)
            .build();

这是我将 ResponseBody 写入 ES 的函数:

private boolean writeResponseBodyToDisk(ResponseBody body) 
    File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "test.pdf");
    try 
        InputStream fis = body.byteStream();
        long length = body.bytes().length;
        byte[] bytes = new byte[(int) length];
        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length && (numRead = fis.read(bytes, offset, bytes.length - offset)) >= 0) 
            offset += numRead;
        

        OutputStream op = new FileOutputStream(dir);
        op.write(bytes);
     catch (Exception ex) 
        Toast.makeText(MainActivity.this, ex.getMessage().toString(), Toast.LENGTH_LONG);
    
    return true;

当我这样放这部分时:

long length = body.bytes().length;

我得到了这个例外:

java.lang.IllegalStateException: 关闭

但是当我像版本更新之前一样离开它时:

long length = body.contentLength();

然后什么都没有发生。在我更新了 okhttp3 的版本之前,这种方式运行良好。

我知道我不能将第一个选项与 bytes.length 一起使用,但我不知道任何替代方案。

【问题讨论】:

【参考方案1】:

只需更改输出流的初始化

    OutputStream op;

    if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)

        ContentValues values = new ContentValues();
        values.put(MediaStore.Files.FileColumns.DISPLAY_NAME,"test.pdf");
        values.put(MediaStore.Files.FileColumns.MIME_TYPE,"application/pdf");
        values.put(MediaStore.Files.FileColumns.RELATIVE_PATH,Environment.DIRECTORY_DOWNLOADS);


        Uri fileUri = getContentResolver().insert(
                MediaStore.Files.getContentUri("external"),
                values
        );

        try 
            op = getContentResolver().openOutputStream(fileUri);
         catch (FileNotFoundException e) 
            e.printStackTrace();
        

    else
        File dir = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "test.pdf");
        try 
            op = new FileOutputStream(dir);
         catch (FileNotFoundException e) 
            e.printStackTrace();
        
    

    try 
        InputStream fis = body.byteStream();
        long length = body.bytes().length;
        byte[] bytes = new byte[(int) length];
        int offset = 0;
        int numRead = 0;
        while (offset < bytes.length && (numRead = fis.read(bytes, offset, bytes.length - offset)) >= 0) 
            offset += numRead;
        
        
        op.write(bytes);
     catch (Exception ex) 
        Toast.makeText(MainActivity.this, ex.getMessage().toString(), Toast.LENGTH_LONG);
    

【讨论】:

你说得对,我刚刚在 android Oreo 上试过,效果很好。我该如何修复它以使其适用于 Q 以上的版本? @Niklaus 我编辑了答案 @Niklaus 我用 Java 重写了代码。如果可行,请帮我一个忙并接受答案。 文件存在于下载文件夹中,但是当我尝试打开它时,它显示“文件无法打开”” @Niklaus 可能是因为文件保存时没有扩展名尝试使用扩展名保存显示名称

以上是关于如何将 ResponseBody(在我的情况下为 PDF)写入外部存储? java.lang.IllegalStateException 的问题:已关闭的主要内容,如果未能解决你的问题,请参考以下文章

允许用户在我的类中定义数组大小而不是使用固定变量的最佳方法是啥,在这种情况下为 8

从任何外部库中增加 tf.data.Dataset 元素(在我的情况下为albumentations)

如何在没有 azure 的情况下为 UWP 注册推送通知?

如何在不为其创建专用网站的情况下为我的应用提供隐私政策?

在没有Android Studio的情况下为Android创建(Cmake)C / C ++库

如何在不将其备份到 iCloud 的情况下为我的应用程序提供演示数据?