调用ThumbnailUtils.createVideoThumbnail获取视频Bitmap返回null问题求助
解决调用ThumbnailUtils.createVideoThumbnail返回null Bitmap的问题
你踩的这个坑其实挺常见的——ThumbnailUtils.createVideoThumbnail()的旧版重载方法根本不支持直接传入content://开头的Uri!它原本是为本地文件的绝对路径设计的,而你从图库或相机拿到的恰恰是content类型的Uri,自然返回null了。
下面给你两个可行的解决方案,优先推荐第一种,兼容性拉满:
方案一:用MediaMetadataRetriever获取缩略图(推荐)
这个类是Android官方提供的媒体元数据检索工具,不管是content Uri还是文件Uri都能轻松处理,而且在各个Android版本上兼容性更好,还能灵活指定获取视频某一帧的时间戳。
直接上代码:
private Bitmap getVideoThumbnail(Uri videoUri) { MediaMetadataRetriever retriever = new MediaMetadataRetriever(); Bitmap thumbnail = null; try { // 传入content Uri和ContentResolver,设置数据源 retriever.setDataSource(getApplicationContext(), videoUri); // 获取视频第一帧作为缩略图,也可以传具体时间戳,比如retriever.getFrameAtTime(1000000)(单位:微秒) thumbnail = retriever.getFrameAtTime(); } catch (Exception e) { // 捕获可能的异常,比如视频文件损坏、权限不足等 e.printStackTrace(); } finally { // 记得释放资源,避免内存泄漏 retriever.release(); } return thumbnail; }
在你的onActivityResult里直接调用这个方法就行:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) { Uri videoUri = data.getData(); Bitmap thumbnail = getVideoThumbnail(videoUri); // 接下来处理你的缩略图即可 } }
方案二:先将content Uri转为文件路径(仅适合低版本或特殊权限场景)
如果你一定要用ThumbnailUtils,那得先把content Uri转换成本地文件的绝对路径,但要注意:Android 10(API 29)及以上因为Scoped Storage的限制,这种方法大概率会失效,除非你申请了MANAGE_EXTERNAL_STORAGE权限(但这个权限很难通过Google Play审核)。
转换Uri到路径的代码示例:
private String getRealPathFromUri(Uri uri) { String filePath = null; // 处理MediaProvider的文档类型Uri if (DocumentsContract.isDocumentUri(this, uri)) { String docId = DocumentsContract.getDocumentId(uri); if ("com.android.providers.media.documents".equals(uri.getAuthority())) { // 拆分docId,格式一般是"video:76"这种 String id = docId.split(":")[1]; String selection = MediaStore.Video.Media._ID + "=?"; String[] selectionArgs = {id}; filePath = getColumnValue(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, selection, selectionArgs); } } else if ("content".equalsIgnoreCase(uri.getScheme())) { // 处理普通的content Uri filePath = getColumnValue(uri, null, null); } return filePath; } // 从ContentResolver中查询获取文件路径 private String getColumnValue(Uri uri, String selection, String[] selectionArgs) { String column = MediaStore.Video.Media.DATA; String[] projection = {column}; // 使用try-with-resources自动关闭Cursor,避免内存泄漏 try (Cursor cursor = getContentResolver().query(uri, projection, selection, selectionArgs, null)) { if (cursor != null && cursor.moveToFirst()) { int columnIndex = cursor.getColumnIndexOrThrow(column); return cursor.getString(columnIndex); } } catch (Exception e) { e.printStackTrace(); } return null; }
然后在onActivityResult里调用:
@Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); if (requestCode == REQUEST_VIDEO_CAPTURE && resultCode == RESULT_OK) { Uri videoUri = data.getData(); String videoPath = getRealPathFromUri(videoUri); if (videoPath != null) { Bitmap thumbnail = ThumbnailUtils.createVideoThumbnail(videoPath, MediaStore.Video.Thumbnails.MINI_KIND); // 处理缩略图 } } }
最后再提醒一句:别忘了权限问题!从图库选视频需要READ_EXTERNAL_STORAGE(Android 13+是READ_MEDIA_VIDEO),相机拍摄需要CAMERA权限,确保你已经在Manifest里声明并动态申请了这些权限。
内容的提问来源于stack exchange,提问作者guillefix
相关产品推荐
相关产品推荐

