AndroidQ(10)分區(qū)存儲完美適配之下載圖片(文件)本地

前言

在上一篇中我們已經講述了AndroidQ(10)分區(qū)存儲適配,包括如何在私有目錄創(chuàng)建文件及文件夾公共目錄下創(chuàng)建文件夾及文件、公有目錄下讀取文件刪除文件等重要功能。

本篇文章將以開發(fā)中的實際情況出發(fā),講述在AndroidQ中如何將圖片下載到公共目錄,簡單來說就是如何將文件圖片復制到另一個文件夾下。

  觸發(fā)場景:gilde已經將圖片緩存在本地,獲取圖片所在的gilde緩存路徑,將圖片復制到自己指定的目錄~
  網絡下載圖片同理復制圖片,只是傳入不同類型的輸入輸出流而已~
相關系列文章

實際操作上手

必要參數(shù):原文件地址、需要復制的本地uri
  • 根據(jù)系統(tǒng)版本獲取不同的文件路徑

    1. AndroidQ以下,可以使用File API操作
    /**
    * AndroidQ以下
    * 創(chuàng)建圖片緩存路徑
    *
    * @param fileName 名稱 包含文件類型
    * @return 返回file類型
    */
    public static File getImageFileCache (String fileName) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            return null;
        }
        //創(chuàng)建項目圖片公共緩存目錄
        File file = new File(Environment.getExternalStorageDirectory()+
                        File.separator +
                        Environment.DIRECTORY_PICTURES +
                        File.separator +
                        "testAndroidQ" +
                        File.separator +
                        "images";);
        if (! file.exists()) {
            file.mkdirs();
        }
        //創(chuàng)建對應圖片的緩存路徑
        return new File(file + File.separator + fileName);
    }
    
    1. AndroidQ以上, 使用MediaStore生成對應文件圖片緩存路徑。不支持File API直接訪問本地文件,如果使用會報無權限訪問異常。
     /**
     * AndroidQ以上保存圖片到公共目錄
     *
     * @param imageName 圖片名稱
     * @param imageType 圖片類型
     * @param relativePath 緩存路徑
     */
    private static Uri insertImageFileIntoMediaStore (String imageName, String imageType,
        String relativePath) {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
            return null;
        }
        if (TextUtils.isEmpty(relativePath)) {
            return null;
        }
        Uri insertUri = null;
        ContentResolver resolver = context.getContentResolver();
        //設置文件參數(shù)到ContentValues中
        ContentValues values = new ContentValues();
        //設置文件名
        values.put(MediaStore.Images.Media.DISPLAY_NAME, imageName);
        //設置文件描述,這里以文件名代替
        values.put(MediaStore.Images.Media.DESCRIPTION, imageName);
        //設置文件類型為image/*
        values.put(MediaStore.Images.Media.MIME_TYPE, "image/" + imageType);
        //注意:MediaStore.Images.Media.RELATIVE_PATH需要targetSdkVersion=29,
        //故該方法只可在Android10的手機上執(zhí)行
        values.put(MediaStore.Images.Media.RELATIVE_PATH, relativePath);
        //EXTERNAL_CONTENT_URI代表外部存儲器
        Uri external = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        //insertUri表示文件保存的uri路徑
        insertUri = resolver.insert(external, values);
        return insertUri;
    }
    
  • 通過兩個路徑地址生成對應的輸入輸出流

    主要方式獲取ContentResolver.openOutputStream(insertUri)

public static boolean copyFile (String sourceFilePath, final Uri insertUri) {
      if (insertUri == null) {
          return false;
      }
      ContentResolver resolver = context.getContentResolver();
      InputStream is = null;//輸入流
      OutputStream os = null;//輸出流
      try {
          os = resolver.openOutputStream(insertUri);
          if (os == null) {
              return false;
          }
          File sourceFile = new File(sourceFilePath);
          if (sourceFile.exists()) { // 文件存在時
              is = new FileInputStream(sourceFile); // 讀入原文件
              //輸入流讀取文件,輸出流寫入指定目錄
              return copyFileWithStream(os, is);
          }
          return false;
      } catch (Exception e) {
          e.printStackTrace();
          return false;
      } finally {
          try {
              if (is != null) {
                  is.close();
              }
              if (os != null) {
                  os.close();
              }
          } catch (IOException e) {
              e.printStackTrace();
          }
      }
}
  • 利用輸入輸出流邊讀邊寫,將文件(圖片)寫入指定路徑
private static boolean copyFileWithStream (OutputStream os, InputStream is) {
      if (os == null || is == null) {
          return false;
      }
      int read = 0;
      while (true) {
          try {
              byte[] buffer = new byte[1444];
              while ((read = is.read(buffer)) != - 1){
                  os.write(buffer, 0, read);
                  os.flush();
              }
              return true;
          } catch (IOException e) {
              e.printStackTrace();
              return false;
          } finally {
              try {
                  os.close();
                  is.close();
              } catch (IOException e) {
                  e.printStackTrace();
              }
          }
      }
}

AndroidQ以下獲取文件輸入輸出流就不貼代碼了,注意區(qū)分就好啦~

加載本地圖片

我們項目中使用的是Glide加載,故示例代碼中也使用Glide。

GlideApp.with(context).load(imageUri);
如果AndroidQ之前使用file://類型加載,兼容10可以采用file轉uri的方式,都可以通過uri加載圖片。

圖片上傳

AndroidQ分區(qū)存儲適配圖片上傳

注意:

  1. 在AndroidQ中公有目錄訪問文件,File API 都無法訪問,即:file://本地path操作文件,本地加載圖片、上傳、下載都不支持,只能通過uri來操作

  2. 如果下載圖片到公共目錄,無需再發(fā)送廣播通知圖片更新;

  3. MediaStore.Images.Media.RELATIVE_PATH需要 targetSdkVersion=29 ,故該方法只可在Android10的手機上執(zhí)行,如果在小于29的系統(tǒng)下調用RELATIVE_PATH會報錯:

android.database.sqlite.SQLiteException: table files has no column named relative_path (code 1 SQLITE_ERROR)
數(shù)據(jù)庫中插入無法找到relative_path字段
本篇代碼適用于文件讀寫、復制、保存圖片到本地等等功能,靈活掌握ContentResolver

后續(xù)會繼續(xù)對AndroidQ分區(qū)存儲實際操作做總結,歡迎關注~

大佬點個贊再走唄~
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

友情鏈接更多精彩內容