Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/351.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 高效加载媒体缩略图_Java_Android_Multithreading_Image - Fatal编程技术网

Java 高效加载媒体缩略图

Java 高效加载媒体缩略图,java,android,multithreading,image,Java,Android,Multithreading,Image,我花了几天时间来解决这个问题,但仍然找不到解决办法。我是Android新手,所以我的代码可能很混乱 我有一个RecyclerView(网格布局),可以显示图像和视频的缩略图。它加载特定文件夹中的媒体文件。但当我启动此活动时,它占用了太多内存 为了加载缩略图,我创建了两个线程 线程1)MediaLoadThread,用于查询SD卡中的媒体文件。它通过游标循环,并将缩略图解码任务队列循环到不同的线程 线程2)ThumbnailLoaderThread对每个缩略图进行解码。它接收内容解析器、媒体类型(

我花了几天时间来解决这个问题,但仍然找不到解决办法。我是Android新手,所以我的代码可能很混乱

我有一个RecyclerView(网格布局),可以显示图像和视频的缩略图。它加载特定文件夹中的媒体文件。但当我启动此活动时,它占用了太多内存

为了加载缩略图,我创建了两个线程

线程1)MediaLoadThread,用于查询SD卡中的媒体文件。它通过游标循环,并将缩略图解码任务队列循环到不同的线程

线程2)ThumbnailLoaderThread对每个缩略图进行解码。它接收内容解析器、媒体类型(图像或视频)和媒体id。它使用basic.getThumbnail()方法。获取缩略图完成后,它将触发对其调用线程(MediaLoadThread)的响应回调

3) 当MediaLoadThread(线程1)收到回调时,它会触发另一个回调,让活动更新给定位置的适配器项。适配器将更新UI,最终缩略图图像视图将从占位符更改为实际缩略图

::这是我的代码::

1)MediaLoadThread.java

@Override
public void run() {
    mMediaDataArr.clear();
    mLoaderThread.start(); // Prepping the thread 2
    mLoaderThread.prepareHandler(); 

      // .... SD Card query stuff .....     

        if (mediaCursor != null && mediaCursor.moveToFirst()) {
            do {
                mMediaDataArr.add(new MediaData(videoCursor.getInt(columnIndexId),
                        mediaCursor.getLong(columnIndexDate), //ID
                        mediaCursor.getInt(columnIndexType), //MEDIA TYPE
                        null); //THUMBNAIL BITMAP (NULL UNTIL THE ACTUAL THUMBNAIL IS DECODED)
            } while (mediaCursor.moveToNext());
            mediaCursor.close();
            mResponseHandler.post(new Runnable() {
                @Override
                public void run() {
                // This callback lets the activity activate the adapter and recyclerview so that the user can interact with recyclerview before the app finishes decoding thumbnails. 
                    mCallback.onVideoLoaded(mMediaDataArr); 
                }
            });

            //Passing tasks to thread 2
            for (int i = 0; i < mMediaDataArr.size(); i++) {
                mLoaderThread.queueTask(
                        mMediaDataArr.get(i).getmMediaType(),
                        i, mMediaDataArr.get(i).getmMediaId());
            }
        }
    }
}

// This is triggered by thread 2 when it finishes decoding 
@Override
public void onThumbnailLoaded(final int position, final Bitmap thumbnail) {
        mResponseHandler.post(new Runnable() {
            @Override
            public void run() {
                mCallback.onThumbnailPrepared(position, thumbnail);
            }
        });
}
public void queueTask(int mediaType, int position, int videoId) {
    mWorkerHandler.obtainMessage(mediaType, position, videoId).sendToTarget();
}

public void prepareHandler() {
    mWorkerHandler = new Handler(getLooper(), new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            int type = msg.what;
            final int position = msg.arg1;
            int videoId = msg.arg2;
            try {
                if (type == MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE) {
                    Bitmap newThumb = MediaStore.Images.Thumbnails
                            .getThumbnail(mCr, videoId,
                                    MediaStore.Images.Thumbnails.MINI_KIND, null);
                    postResult(position, newThumb);

                } else if (type == MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO) {
                    Bitmap newThumb = MediaStore.Video.Thumbnails
                            .getThumbnail(mCr, videoId,
                                    MediaStore.Video.Thumbnails.MINI_KIND, null);
                    postResult(position, newThumb);
                } 
            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;
        }
    });
}

private void postResult(final int position, final Bitmap newThumb) {
        mResponseHandler.post(new Runnable() {
            @Override
            public void run() {
                mCallback.onThumbnailLoaded(position, newThumb);
            }
        });
}
@Override
public void onThumbnailPrepared(int position, Bitmap thumbnail) {
    if (thumbnail != null && position < mData.size()) {
        MediaData updatedData = mData.get(position);
        updatedData.setmThumbnail(thumbnail);
        mData.set(position, updatedData);
        mVideoAdapter.notifyItemChanged(position);
    }
}
3)LibraryActivity.java

@Override
public void run() {
    mMediaDataArr.clear();
    mLoaderThread.start(); // Prepping the thread 2
    mLoaderThread.prepareHandler(); 

      // .... SD Card query stuff .....     

        if (mediaCursor != null && mediaCursor.moveToFirst()) {
            do {
                mMediaDataArr.add(new MediaData(videoCursor.getInt(columnIndexId),
                        mediaCursor.getLong(columnIndexDate), //ID
                        mediaCursor.getInt(columnIndexType), //MEDIA TYPE
                        null); //THUMBNAIL BITMAP (NULL UNTIL THE ACTUAL THUMBNAIL IS DECODED)
            } while (mediaCursor.moveToNext());
            mediaCursor.close();
            mResponseHandler.post(new Runnable() {
                @Override
                public void run() {
                // This callback lets the activity activate the adapter and recyclerview so that the user can interact with recyclerview before the app finishes decoding thumbnails. 
                    mCallback.onVideoLoaded(mMediaDataArr); 
                }
            });

            //Passing tasks to thread 2
            for (int i = 0; i < mMediaDataArr.size(); i++) {
                mLoaderThread.queueTask(
                        mMediaDataArr.get(i).getmMediaType(),
                        i, mMediaDataArr.get(i).getmMediaId());
            }
        }
    }
}

// This is triggered by thread 2 when it finishes decoding 
@Override
public void onThumbnailLoaded(final int position, final Bitmap thumbnail) {
        mResponseHandler.post(new Runnable() {
            @Override
            public void run() {
                mCallback.onThumbnailPrepared(position, thumbnail);
            }
        });
}
public void queueTask(int mediaType, int position, int videoId) {
    mWorkerHandler.obtainMessage(mediaType, position, videoId).sendToTarget();
}

public void prepareHandler() {
    mWorkerHandler = new Handler(getLooper(), new Handler.Callback() {
        @Override
        public boolean handleMessage(Message msg) {
            int type = msg.what;
            final int position = msg.arg1;
            int videoId = msg.arg2;
            try {
                if (type == MediaStore.Files.FileColumns.MEDIA_TYPE_IMAGE) {
                    Bitmap newThumb = MediaStore.Images.Thumbnails
                            .getThumbnail(mCr, videoId,
                                    MediaStore.Images.Thumbnails.MINI_KIND, null);
                    postResult(position, newThumb);

                } else if (type == MediaStore.Files.FileColumns.MEDIA_TYPE_VIDEO) {
                    Bitmap newThumb = MediaStore.Video.Thumbnails
                            .getThumbnail(mCr, videoId,
                                    MediaStore.Video.Thumbnails.MINI_KIND, null);
                    postResult(position, newThumb);
                } 
            } catch (Exception e) {
                e.printStackTrace();
            }
            return true;
        }
    });
}

private void postResult(final int position, final Bitmap newThumb) {
        mResponseHandler.post(new Runnable() {
            @Override
            public void run() {
                mCallback.onThumbnailLoaded(position, newThumb);
            }
        });
}
@Override
public void onThumbnailPrepared(int position, Bitmap thumbnail) {
    if (thumbnail != null && position < mData.size()) {
        MediaData updatedData = mData.get(position);
        updatedData.setmThumbnail(thumbnail);
        mData.set(position, updatedData);
        mVideoAdapter.notifyItemChanged(position);
    }
}
@覆盖
已准备好的公用空白(整型位置,位图缩略图){
if(缩略图!=null&&position
流程是这样的

1) 该活动启动线程1

2) 线程1开始查询文件并启动线程2。它通过光标循环传递媒体id

3) 线程2解码具有给定媒体id的缩略图

4) 解码完成后,线程2将使用结果位图触发对线程1的回调

5) 线程1接收位图并通过回调将位图传递给活动

6) 活动接收缩略图并使用给定位图更新RecyclerView数据

它工作正常,但当系统为此任务分配近50MB内存时。。。考虑到它只加载了100个缩略图,我认为它相当重

:::我所尝试的::

1) 我提取了每个缩略图的URI,并让recyclerview适配器在绑定时加载具有给定URI的图像。它工作正常,没有消耗太多内存,但因为它在项目绑定时加载图像,所以每当我稍微延迟一点滚动屏幕时,它就会重新加载缩略图

2) 我让适配器加载带有直接缩略图路径的缩略图。但当用户清理/.thumbnails文件夹时,它将不起作用

3) 当线程解码缩略图时,我将BitmapFactory.Options samplsize设置为4。但是当它仍然很重,有时甚至更慢的时候

4) 在MediaData对象中,它将缩略图位图作为成员变量保存。因此,在适配器将其加载到ImageView之后,我立即将其设置为null。仍然很重,而且因为我将对象的缩略图设置为null,所以当我向后滚动时,它只显示占位符


我真的不知道。任何帮助都将不胜感激

可以使用图像加载程序库加载图像。该库非常适合图像加载,也可以使用其他库,如etc,来代替手动编码

我尝试使用毕加索,但它加载了实际的图像。不是缩略图。加载图像文件本身不是太重吗(您可以根据布局大小调整图像大小。下面的代码是毕加索。with(上下文)。load(url)。resize(50,50)。centerCrop()。into(图像视图)谢谢。那我应该在哪里添加那一行呢?如果我在适配器的bindViewHolder方法中添加它,每当我滚动时它都会调整图像的大小。好的,我在bindViewHolder方法中添加了这一行。Picasso.with(context)。load(currentData.getUri()).centerCrop().resize(mWidth,mWidth)。进入(holder.mThumbnailIV)稍好一点。但在绑定项目时仍会加载图像。