一、概述
案例:公司測試自己的手機華為mate30,鴻蒙2.0操作系統。用App選擇相冊的時候視頻第一幀加載非常慢(有些視頻第一幀加載不出來),如果第一幀沒加載出來的情況下點擊做預覽就會出現黑屏和ANR。但是其他像小米、vivo、華為其他型號的手機就沒有這個問題。
二、解決方法
找問題過程:
1.由於加載視頻縮略圖的框架用的是Glide,所以最開始的時候懷疑是Glide解碼速度比較慢導致相冊中的圖片加載不出來。最后測試下來並非這個問題,因為其他手機並沒有這個問題。ps:即使是最老舊的手機相冊視頻的第一幀加載速度依然很快。
2.開始定位是否是系統問題,因為公司所有的測試機中都沒有類似或者同樣的問題,只有華為mate30有這個每個問題。百度和google了一圈最終找到這么一篇文章。
https://github.com/zhihu/Matisse/issues/726
解決辦法:
上述問題並沒有實際有效的解決,因為我這邊的手機無法復現了,我讓測試把手機重啟一下試試,結果重啟后此異常消失了。后面再遇到此問題時做再問題補充。
問題補充:
上述方案重啟后確實當時相冊的加載速度還是可以的。但是隔天確有不行了,我不得不調整一下方案,單獨適配mate30機型。調整后相冊加載變得正常了。
解決步驟:
1.判斷手機是否是Android10系統
2.判斷手機系統是華為Harmony OS系統
3.判斷得到的路徑是content://開頭的路徑
4.如果三個條件都滿足則把content://開頭的路徑轉為絕對路徑,即:/storage/emulated/0/DCIM/Camera/share_7b2a295b74f8b18d3bd3c40ada8bb304.mp4 形式的路徑,轉換后相冊加載速度正常。
ps:相關轉換代碼如下:
/** * 返回條件: * 1.如果是Android10.0的系統 * 2.且手機系統是華為的 * 3.路徑是content://開頭的 * @return */ public static String getNewPath(Context context,String path){ if(SdkVersionUtils.checkedAndroid_Q_31()&&SdkVersionUtils.isHarmonyOSa()&&PictureMimeType.isContent(path)){ return getPath(context, Uri.parse(path)); } return path; } /** * Get a file path from a Uri. This will get the the path for Storage Access * Framework Documents, as well as the _data field for the MediaStore and * other file-based ContentProviders.<br> * <br> * Callers should check whether the path is local before assuming it * represents a local file. * * @param context The context. * @param uri The Uri to query. * @author paulburke */ @SuppressLint("NewApi") public static String getPath(final Context context, final Uri uri) { final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT; // DocumentProvider if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) { if (isExternalStorageDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; if ("primary".equalsIgnoreCase(type)) { if (SdkVersionUtils.checkedAndroid_Q()) { return context.getExternalFilesDir(Environment.DIRECTORY_PICTURES) + "/" + split[1]; } else { return Environment.getExternalStorageDirectory() + "/" + split[1]; } } // TODO handle non-primary volumes } // DownloadsProvider else if (isDownloadsDocument(uri)) { final String id = DocumentsContract.getDocumentId(uri); final Uri contentUri = ContentUris.withAppendedId( Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); return getDataColumn(context, contentUri, null, null); } // MediaProvider else if (isMediaDocument(uri)) { final String docId = DocumentsContract.getDocumentId(uri); final String[] split = docId.split(":"); final String type = split[0]; Uri contentUri = null; if ("image".equals(type)) { contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; } else if ("video".equals(type)) { contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; } else if ("audio".equals(type)) { contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; } final String selection = "_id=?"; final String[] selectionArgs = new String[]{ split[1] }; return getDataColumn(context, contentUri, selection, selectionArgs); } } // MediaStore (and general) else if ("content".equalsIgnoreCase(uri.getScheme())) { // Return the remote address if (isGooglePhotosUri(uri)) { return uri.getLastPathSegment(); } return getDataColumn(context, uri, null, null); } // File else if ("file".equalsIgnoreCase(uri.getScheme())) { return uri.getPath(); } return null; }
使用的時候只需要調用,getNewPath方法獲取路徑即可。加載相冊的庫依然使用的是Glide
String newPath = PictureFileUtils.getNewPath(context,path);