使用 MediaStore 和 ContentValues 在 Android 11 / API 30 重命名视频
Video renaming on Android 11 / API 30 using MediaStore and ContentValues
下面的代码在 Android 11 之前可以正常工作。我已经在 Android 9 上测试过它并且可以工作。
获取视频基本信息的方法:
private static void videoRename ( AppCompatActivity activity , VideoModel model , VideosLoader videosLoader ) {
String videoTitleWithExtension = model.getVideoTitle ( );
int extensionIndex = videoTitleWithExtension.lastIndexOf ( '.' );
final String videoTitleWithoutExtension;
String extensionValue;
if ( extensionIndex > 0 ) {
videoTitleWithoutExtension = videoTitleWithExtension.substring ( 0 , extensionIndex );
extensionValue = videoTitleWithExtension.substring ( extensionIndex, videoTitleWithExtension.length ( ) );
} else {
videoTitleWithoutExtension = videoTitleWithExtension;
extensionValue = "";
}
showSelectedVideoRenameDialog ( activity , videoTitleWithoutExtension, model.getPath ( ) , extensionValue, model.getVideoId ( ) , videosLoader );
}
正在将数据传递到对话框,然后显示对话框:
private static void showSelectedVideoRenameDialog ( final AppCompatActivity activity, final String videoTitleWithoutExtension , final String videoPath, final String extensionValue, final long videoId , final VideosLoader videosLoader ) {
final AlertDialog dialog = new AlertDialog.Builder ( activity ).create ( );
LayoutInflater inflater = LayoutInflater.from ( activity );
View v = inflater.inflate ( R.layout.layout_video_rename, null );
final TextInputEditText input = v.findViewById ( R.id.video_rename_edit_text );
input.setText ( videoTitleWithoutExtension );
input.setHint ( videoTitleWithoutExtension );
Button confirmButton = v.findViewById ( R.id.renameButton );
Button cancelButton = v.findViewById ( R.id.cancelButton );
dialog.setView ( v );
cancelButton.setOnClickListener ( new View.OnClickListener ( ) {
@Override
public void onClick ( View p1 ) {
dialog.dismiss ( );
}
} );
confirmButton.setOnClickListener ( new View.OnClickListener ( ) {
@Override
public void onClick ( View p1 ) {
final String typedName = input.getText ( ).toString ( );
final File originalName = new File ( videoPath );
final File newFileName = new File ( videoPath.replace ( videoTitleWithoutExtension , typedName ) );
if ( typedName.length ( ) == 0 ) {
input.setError ( "Name can't be empty" );
} else if ( newFileName.exists ( ) ) {
input.setError ( "File name already exists" );
} else {
String newTitleWithExtension = typedName + extensionValue;
originalName.renameTo ( newFileName );
String newFilePath = newFileName.toString ( );
videosLoader.updateOnVideoRenamed ( videoId , newFilePath , newTitleWithExtension );
videosLoader.updateOnMediaStoreChanged ( );
dialog.dismiss ( );
}
}
} );
dialog.show ( );
}
最后,使用 ContentValues
和 MediaStore
更新值:
@Override
public void updateOnVideoRenamed ( long id, String newPath, String newTitle ) {
try {
ContentValues contentValues = new ContentValues(2);
contentValues.put(MediaStore.Video.Media.DATA, newPath);
contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, newTitle);
mContext.getContentResolver ( ).update ( MediaStore.Video.Media.EXTERNAL_CONTENT_URI , contentValues, MediaStore.Video.Media._ID + "=" + id, null );
} catch (Exception e) {
Toast.makeText( mContext , "Can't rename on Android 11: " + " " + e.getMessage() , Toast.LENGTH_SHORT).show();
}
}
这最后一步显然会抛出 java.lang.IllegalArgumentException
。
我尝试了 的答案,但仍然没有成功。我可能遗漏了什么。
P.S。对于我使用默认三星文件管理器创建的文件夹中的视频,重命名也失败。
首先,我必须将此权限添加到清单中才能访问设备上的所有文件:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
然后我将这一行添加到 application
标签:
android:requestLegacyExternalStorage="true"
现在更改视频名称后,您需要使用新名称更新媒体存储:
if (ContextUtils.isAndroidR()) {
Uri mUri = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI , videoId);
try {
ContentValues contentValues = new ContentValues(3);
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
mContext.getContentResolver().update(mUri, contentValues, null, null);
contentValues.clear();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, newTitle);
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
mContext.getContentResolver().update(mUri, contentValues, null, null);
} catch (Exception exception) {
if (ContextUtils.isAndroidQ()) {
RecoverableSecurityException recoverableSecurityException;
if (exception instanceof RecoverableSecurityException) {
recoverableSecurityException = (RecoverableSecurityException) exception;
} else {
ContextUtils.makeShortToast( "Maybe make sure you request permissions first?" );
}
try {
ContentResolver contentResolver = mContext.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
contentResolver.update(mUri, contentValues, null, null);
contentValues.clear();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, newTitle);
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
contentResolver.update(mUri, contentValues, null, null);
} catch (Exception e) {
e.printStackTrace();
ContextUtils.makeShortToast( String.valueOf(e) );
}
} else {
throw new RuntimeException ( exception.getMessage() , exception );
}
}
} else {
ContentValues contentValues = new ContentValues(2);
contentValues.put(MediaStore.Video.Media.DATA, newPath);
contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, newTitle);
Uri extUri = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
mContext.getContentResolver().update(extUri , contentValues, MediaStore.Video.Media._ID + "=" + videoId, null);
}
这就是我在 Android 11 上重命名视频的方式,可以毫无问题地工作。
下面的代码在 Android 11 之前可以正常工作。我已经在 Android 9 上测试过它并且可以工作。
获取视频基本信息的方法:
private static void videoRename ( AppCompatActivity activity , VideoModel model , VideosLoader videosLoader ) {
String videoTitleWithExtension = model.getVideoTitle ( );
int extensionIndex = videoTitleWithExtension.lastIndexOf ( '.' );
final String videoTitleWithoutExtension;
String extensionValue;
if ( extensionIndex > 0 ) {
videoTitleWithoutExtension = videoTitleWithExtension.substring ( 0 , extensionIndex );
extensionValue = videoTitleWithExtension.substring ( extensionIndex, videoTitleWithExtension.length ( ) );
} else {
videoTitleWithoutExtension = videoTitleWithExtension;
extensionValue = "";
}
showSelectedVideoRenameDialog ( activity , videoTitleWithoutExtension, model.getPath ( ) , extensionValue, model.getVideoId ( ) , videosLoader );
}
正在将数据传递到对话框,然后显示对话框:
private static void showSelectedVideoRenameDialog ( final AppCompatActivity activity, final String videoTitleWithoutExtension , final String videoPath, final String extensionValue, final long videoId , final VideosLoader videosLoader ) {
final AlertDialog dialog = new AlertDialog.Builder ( activity ).create ( );
LayoutInflater inflater = LayoutInflater.from ( activity );
View v = inflater.inflate ( R.layout.layout_video_rename, null );
final TextInputEditText input = v.findViewById ( R.id.video_rename_edit_text );
input.setText ( videoTitleWithoutExtension );
input.setHint ( videoTitleWithoutExtension );
Button confirmButton = v.findViewById ( R.id.renameButton );
Button cancelButton = v.findViewById ( R.id.cancelButton );
dialog.setView ( v );
cancelButton.setOnClickListener ( new View.OnClickListener ( ) {
@Override
public void onClick ( View p1 ) {
dialog.dismiss ( );
}
} );
confirmButton.setOnClickListener ( new View.OnClickListener ( ) {
@Override
public void onClick ( View p1 ) {
final String typedName = input.getText ( ).toString ( );
final File originalName = new File ( videoPath );
final File newFileName = new File ( videoPath.replace ( videoTitleWithoutExtension , typedName ) );
if ( typedName.length ( ) == 0 ) {
input.setError ( "Name can't be empty" );
} else if ( newFileName.exists ( ) ) {
input.setError ( "File name already exists" );
} else {
String newTitleWithExtension = typedName + extensionValue;
originalName.renameTo ( newFileName );
String newFilePath = newFileName.toString ( );
videosLoader.updateOnVideoRenamed ( videoId , newFilePath , newTitleWithExtension );
videosLoader.updateOnMediaStoreChanged ( );
dialog.dismiss ( );
}
}
} );
dialog.show ( );
}
最后,使用 ContentValues
和 MediaStore
更新值:
@Override
public void updateOnVideoRenamed ( long id, String newPath, String newTitle ) {
try {
ContentValues contentValues = new ContentValues(2);
contentValues.put(MediaStore.Video.Media.DATA, newPath);
contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, newTitle);
mContext.getContentResolver ( ).update ( MediaStore.Video.Media.EXTERNAL_CONTENT_URI , contentValues, MediaStore.Video.Media._ID + "=" + id, null );
} catch (Exception e) {
Toast.makeText( mContext , "Can't rename on Android 11: " + " " + e.getMessage() , Toast.LENGTH_SHORT).show();
}
}
这最后一步显然会抛出 java.lang.IllegalArgumentException
。
我尝试了
P.S。对于我使用默认三星文件管理器创建的文件夹中的视频,重命名也失败。
首先,我必须将此权限添加到清单中才能访问设备上的所有文件:
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/>
然后我将这一行添加到 application
标签:
android:requestLegacyExternalStorage="true"
现在更改视频名称后,您需要使用新名称更新媒体存储:
if (ContextUtils.isAndroidR()) {
Uri mUri = ContentUris.withAppendedId(MediaStore.Video.Media.EXTERNAL_CONTENT_URI , videoId);
try {
ContentValues contentValues = new ContentValues(3);
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
mContext.getContentResolver().update(mUri, contentValues, null, null);
contentValues.clear();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, newTitle);
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
mContext.getContentResolver().update(mUri, contentValues, null, null);
} catch (Exception exception) {
if (ContextUtils.isAndroidQ()) {
RecoverableSecurityException recoverableSecurityException;
if (exception instanceof RecoverableSecurityException) {
recoverableSecurityException = (RecoverableSecurityException) exception;
} else {
ContextUtils.makeShortToast( "Maybe make sure you request permissions first?" );
}
try {
ContentResolver contentResolver = mContext.getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 1);
contentResolver.update(mUri, contentValues, null, null);
contentValues.clear();
contentValues.put(MediaStore.Files.FileColumns.DISPLAY_NAME, newTitle);
contentValues.put(MediaStore.Files.FileColumns.IS_PENDING, 0);
contentResolver.update(mUri, contentValues, null, null);
} catch (Exception e) {
e.printStackTrace();
ContextUtils.makeShortToast( String.valueOf(e) );
}
} else {
throw new RuntimeException ( exception.getMessage() , exception );
}
}
} else {
ContentValues contentValues = new ContentValues(2);
contentValues.put(MediaStore.Video.Media.DATA, newPath);
contentValues.put(MediaStore.Video.Media.DISPLAY_NAME, newTitle);
Uri extUri = MediaStore.Video.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
mContext.getContentResolver().update(extUri , contentValues, MediaStore.Video.Media._ID + "=" + videoId, null);
}
这就是我在 Android 11 上重命名视频的方式,可以毫无问题地工作。