20241010uniapp学习工作-安卓easyphoto第三方选图片慢问题解决

这事实在是太惭愧了.

国庆假期前一周, 有客户反映安卓端app选择图片打开相册加载很慢.

这个问题涉及第三方easyphoto, 看起来又是性能问题, 这两个都是我很害怕的.

于是我上来就预设, 这个问题我很可能改不好, 这是个超级大难题, 需要很长时间, 最终也未必有结果.

我自然认为是那个第三方不行, 得用系统自带的选择图片功能才行, 于是投身于安卓 intent 方式选择图片的研究中.

中间遇到了 intent 方式选择图片后的路径问题, 便研究起安卓文件系统来, 发现把选择到的视频存储到应用的专属目录即可绕过路径问题.

但 intent 方式只能单独选择图片, 或者单独选择视频, 这样的话用户会觉得很不适应, 因为以前都是视频和图片可以一起选的.

我便和领导反映了这个问题.

领导则让我定位一下 easyphoto 这个第三方选图片时, 究竟哪里慢.

我这才隐约意识到, 我从头到尾根本就没有去定位问题具体在什么位置.

于是今天早上来了便开始看 easyphoto 的代码, 根据文件名判断功能, 然后进去看具体方法, 找到了这个方法, 然后运行发现这个方法很慢.

private synchronized void initAlbum(Context context) {
        album.clear();
        long now = System.currentTimeMillis();
        if (Setting.selectedPhotos.size() > Setting.count) {
            throw new RuntimeException("AlbumBuilder: 默认勾选的图片张数不能大于设置的选择数!" + "|默认勾选图片张数:" + Setting.selectedPhotos.size() + "|设置的选择数:" + Setting.count);
        }
        boolean canReadWidth =
                android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN;
//        boolean isQ = android.os.Build.VERSION.SDK_INT == Build.VERSION_CODES.Q;
        final String sortOrder = MediaStore.Files.FileColumns.DATE_MODIFIED + " DESC";

        Uri contentUri;
        String selection = null;
        String[] selectionAllArgs = null;

        if (Setting.isOnlyVideo()) {
            contentUri = MediaStore.Video.Media.getContentUri("external");

        } else if (!Setting.showVideo) {
            contentUri = MediaStore.Images.Media.getContentUri("external");

        } else {
            contentUri = MediaStore.Files.getContentUri("external");
            selection =
                    "(" + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?" + " OR " + MediaStore.Files.FileColumns.MEDIA_TYPE + "=?)";
            selectionAllArgs =
                    new String[]{String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE),
                            String.valueOf(MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO)};
        }

        ContentResolver contentResolver = context.getContentResolver();


        List<String> projectionList = new ArrayList<String>();
        projectionList.add(MediaStore.Files.FileColumns._ID);
//        if (isQ) {
//            projectionList.add(MediaStore.MediaColumns.RELATIVE_PATH);
//        }else {
        projectionList.add(MediaStore.MediaColumns.DATA);
//        }
        projectionList.add(MediaStore.MediaColumns.DISPLAY_NAME);
        projectionList.add(MediaStore.MediaColumns.DATE_MODIFIED);
        projectionList.add(MediaStore.MediaColumns.MIME_TYPE);
        projectionList.add(MediaStore.MediaColumns.SIZE);
        projectionList.add(MediaStore.MediaColumns.BUCKET_DISPLAY_NAME);

        if (!Setting.useWidth) {
            if (Setting.minWidth != 1 && Setting.minHeight != 1)
                Setting.useWidth = true;
        }
        if (canReadWidth) {
            if (Setting.useWidth) {
                projectionList.add(MediaStore.MediaColumns.WIDTH);
                projectionList.add(MediaStore.MediaColumns.HEIGHT);
                if (!Setting.isOnlyVideo())
                    projectionList.add(MediaStore.MediaColumns.ORIENTATION);
            }
        }

        if (Setting.showVideo) {
            projectionList.add(MediaStore.MediaColumns.DURATION);
        }

        projections = projectionList.toArray(new String[0]);

        Cursor cursor = contentResolver.query(contentUri, projections, selection,
                selectionAllArgs, sortOrder);
        if (cursor == null) {
//            Log.d(TAG, "call: " + "Empty photos");
        } else if (cursor.moveToFirst()) {
            String albumItem_all_name = getAllAlbumName(context);
            String albumItem_video_name =
                    context.getString(R.string.selector_folder_video_easy_photos);

            int albumNameCol = cursor.getColumnIndex(MediaStore.MediaColumns.BUCKET_DISPLAY_NAME);
            int durationCol = cursor.getColumnIndex(MediaStore.MediaColumns.DURATION);
            int WidthCol = 0;
            int HeightCol = 0;
            int orientationCol = -1;
            if (canReadWidth && Setting.useWidth) {
                WidthCol = cursor.getColumnIndex(MediaStore.MediaColumns.WIDTH);
                HeightCol = cursor.getColumnIndex(MediaStore.MediaColumns.HEIGHT);
                orientationCol = cursor.getColumnIndex(MediaStore.MediaColumns.ORIENTATION);
            }
            boolean hasTime = durationCol > 0;

            do {
                long id = cursor.getLong(0);
                String path = cursor.getString(1);
                String name = cursor.getString(2);
                long dateTime = cursor.getLong(3);
                String type = cursor.getString(4);
                long size = cursor.getLong(5);
                long duration = 0;


                if (TextUtils.isEmpty(path) || TextUtils.isEmpty(type)) {
                    continue;
                }

                if (size < Setting.minSize) {
                    continue;
                }

                boolean isVideo = type.contains(Type.VIDEO);// 是否是视频

                int width = 0;
                int height = 0;
                int orientation = 0;
                if (isVideo) {
                    if (hasTime)
                        duration = cursor.getLong(durationCol);
                    if (duration <= Setting.videoMinSecond || duration >= Setting.videoMaxSecond) {
                        continue;
                    }
                } else {
                    if (orientationCol != -1) {
                        orientation = cursor.getInt(orientationCol);
                    }
                    if (!Setting.showGif) {
                        if (path.endsWith(Type.GIF) || type.endsWith(Type.GIF)) {
                            continue;
                        }
                    }
                    if (Setting.useWidth) {
                        if (canReadWidth) {
                            width = cursor.getInt(WidthCol);
                            height = cursor.getInt(HeightCol);
                        }
                        if (width == 0 || height == 0) {
                            BitmapFactory.Options options = new BitmapFactory.Options();
                            options.inJustDecodeBounds = true;
                            BitmapFactory.decodeFile(path, options);
                            width = options.outWidth;
                            height = options.outHeight;
                        }

                        if (orientation == 90 || orientation == 270) {
                            int temp = width;
                            width = height;
                            height = temp;
                        }

                        if (width < Setting.minWidth || height < Setting.minHeight) {
                            continue;
                        }

                    }
                }

                Uri uri = ContentUris.withAppendedId(isVideo ?
                        MediaStore.Video.Media.getContentUri("external") :
                        MediaStore.Images.Media.getContentUri("external"), id);

//某些机型,特定情况下三方应用或用户操作删除媒体文件时,没有通知媒体库,导致媒体库表中还有其数据,但真实文件已经不存在
                File file = new File(path);
                if (!file.isFile()) {
                    continue;
                }

                Photo imageItem = new Photo(name, uri, path, dateTime, width, height, orientation
                        , size,
                        duration, type);
                if (!Setting.selectedPhotos.isEmpty()) {
                    int selectSize = Setting.selectedPhotos.size();
                    for (int i = 0; i < selectSize; i++) {
                        Photo selectedPhoto = Setting.selectedPhotos.get(i);
                        if (path.equals(selectedPhoto.path)) {
                            imageItem.selectedOriginal = Setting.selectedOriginal;
                            Result.addPhoto(imageItem);
                        }
                    }
                }

                // 初始化“全部”专辑
                if (album.isEmpty()) {
                    // 用第一个图片作为专辑的封面
                    album.addAlbumItem(albumItem_all_name, "", path, uri);
                }
                // 把图片全部放进“全部”专辑
                album.getAlbumItem(albumItem_all_name).addImageItem(imageItem);

                if (Setting.showVideo && isVideo && !albumItem_video_name.equals(albumItem_all_name)) {
                    album.addAlbumItem(albumItem_video_name, "", path, uri);
                    album.getAlbumItem(albumItem_video_name).addImageItem(imageItem);
                }

                // 添加当前图片的专辑到专辑模型实体中
                String albumName;
                String folderPath;
                if (albumNameCol > 0) {
                    albumName = cursor.getString(albumNameCol);
                    folderPath = albumName;
                } else {
                    File parentFile = new File(path).getParentFile();
                    if (null == parentFile) {
                        continue;
                    }
                    folderPath = parentFile.getAbsolutePath();
                    albumName = StringUtils.getLastPathSegment(folderPath);
                }

                album.addAlbumItem(albumName, folderPath, path, uri);
                album.getAlbumItem(albumName).addImageItem(imageItem);
            } while (cursor.moveToNext() && canRun);
            cursor.close();
            if (!Setting.selectedPhotos.isEmpty() && Setting.isSequentialSelectedPhotos) {
                int selectSize = Setting.selectedPhotos.size();
                int photoSize = Result.photos.size();
                ArrayList<Photo> tempList = new ArrayList<>(photoSize);
                for (int i = 0; i < selectSize; i++) {
                    for (int j = 0; j < photoSize; j++) {
                        if (Result.photos.get(j).path.equals(Setting.selectedPhotos.get(i).path)){
                            tempList.add(i,Result.photos.get(j));
                        }
                    }
                }
                Result.photos = tempList;
            }
        }
        Log.d(TAG, "initAlbum: " + (System.currentTimeMillis() - now));
    }

 这是个超长的方法, 代码很多, 我又一次预设这玩意我看不懂, 就算看懂了, 它这是一下子把图片加载进来, 改为分批加载很难, 就算改好了怎么分批显示也好难.

总之, 我全程都在觉得难, 还想了很多合理的原因. 就是没去定位问题出在哪?

我定位到这个方法, 却没再仔细定位这么多代码中, 究竟哪一句导致的加载过慢.

这时候我又跟领导反映这个问题一时半会解决不了.

领导也没说什么, 直接过来看了一会, 打了断点一步步调试下去, 发现是 do while 循环遍历这块比较慢, 那问题就在于这个循环吗?

如果是我, 肯定就又认为, 循环这玩意慢没法解决啊.

然后领导看了循环里的代码, 找到了这样一段代码,

//某些机型,特定情况下三方应用或用户操作删除媒体文件时,没有通知媒体库,导致媒体库表中还有其数据,但真实文件已经不存在
                File file = new File(path);
                if (!file.isFile()) {
                    continue;
                }

这块会不会导致慢, 这就不是我能看出来的, 可能打断点也试不出来, 因为这段代码不循环的话应该也不慢.

领导之所以能判断是这段导致的慢, 是因为他知道导致速度慢的原因一般就两个, 一个是网络, 一个是磁盘读写.

然后领导把这段代码注释掉, 速度一下子提高了80%.

至此, 问题解决.

虽然领导没说什么, 我真实羞愧的无地自容, 我至少应该定位到这个循环, 再去找领导支持的. 结果东冲西撞绕来绕去, 还牢骚满腹, 问题还丝毫没得到解决.

以后遇到问题, 一定要在代码层面, 具体到某行某段代码层面, 定位到问题的起因.

还有, 不要心里预设问题太难. 这样的自我限制会导致什么也做不成.

另外, 那段代码之所以可以注释掉, 是因为绝大多数情况下, 不会出现那种情况.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值