Android 10之前版本主要步驟
- 請求讀寫權(quán)限
- 圖片/視頻下載到/storage/emulated/0/Android/data/包名/xxx
- 復(fù)制到系統(tǒng)相冊目錄下
- 掃描媒體庫
Android 10及以上版本主要步驟
- 請求讀寫權(quán)限
- 圖片/視頻下載到/storage/emulated/0/Android/data/包名/xxx
- 創(chuàng)建ContentValues,寫入要保存的信息
- 調(diào)用ContentResolver插入ContentValues到相冊中,此時會返回新創(chuàng)建的相冊uri
- 將原先的文件復(fù)制到該uri中(android11及以上必須這么干)
- 發(fā)送廣播,掃描媒體庫
關(guān)鍵代碼:
public class SaveUtils {
private static final String TAG = "SaveUtils";
/**
* 將圖片文件保存到系統(tǒng)相冊
*/
public static boolean saveImgFileToAlbum(Context context, String imageFilePath) {
Log.d(TAG, "saveImgToAlbum() imageFile = [" + imageFilePath + "]");
try {
Bitmap bitmap = BitmapFactory.decodeFile(imageFilePath);
return saveBitmapToAlbum(context, bitmap);
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* 將bitmap保存到系統(tǒng)相冊
*/
public static boolean saveBitmapToAlbum(Context context, Bitmap bitmap) {
if (bitmap == null) return false;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
return saveBitmapToAlbumBeforeQ(context, bitmap);
} else {
return saveBitmapToAlbumAfterQ(context, bitmap);
}
}
@RequiresApi(api = Build.VERSION_CODES.Q)
private static boolean saveBitmapToAlbumAfterQ(Context context, Bitmap bitmap) {
Uri contentUri;
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else {
contentUri = MediaStore.Images.Media.INTERNAL_CONTENT_URI;
}
ContentValues contentValues = getImageContentValues(context);
Uri uri = context.getContentResolver().insert(contentUri, contentValues);
if (uri == null) {
return false;
}
OutputStream os = null;
try {
os = context.getContentResolver().openOutputStream(uri);
bitmap.compress(Bitmap.CompressFormat.JPEG, 50, os);
// if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
// Files.copy(bitmapFile.toPath(), os);
// }
contentValues.clear();
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
context.getContentResolver().update(uri, contentValues, null, null);
return true;
} catch (Exception e) {
context.getContentResolver().delete(uri, null, null);
e.printStackTrace();
return false;
} finally {
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static boolean saveBitmapToAlbumBeforeQ(Context context, Bitmap bitmap) {
File picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File destFile = new File(picDir, context.getPackageName() + File.separator + System.currentTimeMillis() + ".jpg");
// FileUtils.copy(imageFile, destFile.getAbsolutePath());
OutputStream os = null;
boolean result = false;
try {
if (!destFile.exists()) {
destFile.getParentFile().mkdirs();
destFile.createNewFile();
}
os = new BufferedOutputStream(new FileOutputStream(destFile));
result = bitmap.compress(Bitmap.CompressFormat.JPEG, 50, os);
if (!bitmap.isRecycled()) bitmap.recycle();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
MediaScannerConnection.scanFile(
context,
new String[]{destFile.getAbsolutePath()},
new String[]{"image/*"},
(path, uri) -> {
Log.d(TAG, "saveImgToAlbum: " + path + " " + uri);
// Scan Completed
});
return result;
}
/**
* 獲取圖片的ContentValue
*
* @param context
*/
@RequiresApi(api = Build.VERSION_CODES.Q)
public static ContentValues getImageContentValues(Context context) {
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Images.Media.DISPLAY_NAME, System.currentTimeMillis() + ".jpg");
contentValues.put(MediaStore.Images.Media.MIME_TYPE, "image/*");
contentValues.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM + File.separator + context.getPackageName());
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 1);
contentValues.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
contentValues.put(MediaStore.Images.Media.DATE_MODIFIED, System.currentTimeMillis());
contentValues.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
return contentValues;
}
/**
* 將視頻保存到系統(tǒng)相冊
*/
public static boolean saveVideoToAlbum(Context context, String videoFile) {
Log.d(TAG, "saveVideoToAlbum() videoFile = [" + videoFile + "]");
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
return saveVideoToAlbumBeforeQ(context, videoFile);
} else {
return saveVideoToAlbumAfterQ(context, videoFile);
}
}
private static boolean saveVideoToAlbumAfterQ(Context context, String videoFile) {
try {
ContentResolver contentResolver = context.getContentResolver();
File tempFile = new File(videoFile);
ContentValues contentValues = getVideoContentValues(context, tempFile, System.currentTimeMillis());
Uri uri = contentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, contentValues);
copyFileAfterQ(context, contentResolver, tempFile, uri);
contentValues.clear();
contentValues.put(MediaStore.MediaColumns.IS_PENDING, 0);
context.getContentResolver().update(uri, contentValues, null, null);
context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
private static boolean saveVideoToAlbumBeforeQ(Context context, String videoFile) {
File picDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM);
File tempFile = new File(videoFile);
File destFile = new File(picDir, context.getPackageName() + File.separator + tempFile.getName());
FileInputStream ins = null;
BufferedOutputStream ous = null;
try {
ins = new FileInputStream(tempFile);
ous = new BufferedOutputStream(new FileOutputStream(destFile));
long nread = 0L;
byte[] buf = new byte[1024];
int n;
while ((n = ins.read(buf)) > 0) {
ous.write(buf, 0, n);
nread += n;
}
MediaScannerConnection.scanFile(
context,
new String[]{destFile.getAbsolutePath()},
new String[]{"video/*"},
(path, uri) -> {
Log.d(TAG, "saveVideoToAlbum: " + path + " " + uri);
// Scan Completed
});
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
} finally {
try {
if (ins != null) {
ins.close();
}
if (ous != null) {
ous.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
private static void copyFileAfterQ(Context context, ContentResolver localContentResolver, File tempFile, Uri localUri) throws IOException {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q &&
context.getApplicationInfo().targetSdkVersion >= Build.VERSION_CODES.Q) {
//拷貝文件到相冊的uri,android10及以上得這么干,否則不會顯示。可以參考ScreenMediaRecorder的save方法
OutputStream os = localContentResolver.openOutputStream(localUri);
Files.copy(tempFile.toPath(), os);
os.close();
tempFile.delete();
}
}
/**
* 獲取視頻的contentValue
*/
public static ContentValues getVideoContentValues(Context context, File paramFile, long timestamp) {
ContentValues localContentValues = new ContentValues();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
localContentValues.put(MediaStore.Video.Media.RELATIVE_PATH, Environment.DIRECTORY_DCIM
+ File.separator + context.getPackageName());
}
localContentValues.put(MediaStore.Video.Media.TITLE, paramFile.getName());
localContentValues.put(MediaStore.Video.Media.DISPLAY_NAME, paramFile.getName());
localContentValues.put(MediaStore.Video.Media.MIME_TYPE, "video/mp4");
localContentValues.put(MediaStore.Video.Media.DATE_TAKEN, timestamp);
localContentValues.put(MediaStore.Video.Media.DATE_MODIFIED, timestamp);
localContentValues.put(MediaStore.Video.Media.DATE_ADDED, timestamp);
localContentValues.put(MediaStore.Video.Media.SIZE, paramFile.length());
return localContentValues;
}
}