使用LRUCACHE解决加载本地大量图片卡顿及OOM问题
2017-05-10 15:12
531 查看
今天测试了一下之前写的一个从本地加载图片并显示的功能,因为以前测试的时候一次性显示的图片比较少,所以就没发现有卡顿以及进入界面比较慢的问题,但是今天想看一下传入很多图片之后的界面效果,所以就加载了很多图片,传入图片之后一开始进入界面,发现出错,出错运用是因为我往Adapter里面传的参数有一项是ArrayList<Bitmap>,因为一次性传入太多的BitMap,所以越界了,导致程序崩溃,然后改成传路径,这个问题得到解决,但是又发现进入界面的时候特别慢,而且往下滑动的时候也是特别的卡顿,我在重写Adapter的时候用到了优化,但是还是特别卡顿,然后想到我每加载一张图片都是去根据路径去读文件,所以导致卡顿现象特别严重,而且进入的时候也是因为每张图片都去读一下文件,所以进入特别慢,有时候甚至出现OOM的问题。这时突然间感觉自己以前写的时候脑子估计是抽风了,竟然犯了这么弱智的问题,每次读文件是很耗时的,所以程序不崩溃才怪。因此感觉使用缓存的技术来修改自己的程序。因为这次又用到了LruCache技术,所以顺便写一下使用过程吧。
其实方法跟网上大部分讲解的代码都类似,只是把从网络下载图片部分改成从本地加载,而且因为这个程序的特殊性,所以加载的图片不能有相同路径的图片,因为所有的键值对设置我都是以图片的路径做的,所以如果路径相同的话有可能会使图片显示不出来。
其实方法跟网上大部分讲解的代码都类似,只是把从网络下载图片部分改成从本地加载,而且因为这个程序的特殊性,所以加载的图片不能有相同路径的图片,因为所有的键值对设置我都是以图片的路径做的,所以如果路径相同的话有可能会使图片显示不出来。
public class WineListAdapter extends BaseAdapter implements AbsListView.OnScrollListener { // 从本地加载图片的线程集合 private List<ImageDownloadTask> mDownloadTaskList; private LruCache<String, Bitmap> mLruCache; // 引用外部的变量 private WeakReference<GridView> mGridView; private WeakReference<List<String>> urls; private WeakReference<List<String>> names; private WeakReference<Context> mContext; // 可见项的第一项的index private int mFirstVisibleIndex; // 可见项的个数 private int mVisibleItemCount; // 是不是第一次打开Activity private boolean isFirstOpen = true; public WineListAdapter(Context context, GridView mGridView, List<String> urls, List<String> names) { this.mContext = new WeakReference<Context>(context); this.urls = new WeakReference<List<String>>(urls); this.names = new WeakReference<List<String>>(names); this.mGridView = new WeakReference<GridView>(mGridView); this.mGridView.get().setOnScrollListener(this); mDownloadTaskList = new ArrayList<>(); initCache(); } private void initCache() { // 获取应用的max heap size final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); // Android官方教学文档推荐LruCache的size为heap size的1/8 int cacheSize = maxMemory / 8; mLruCache = new LruCache<String, Bitmap>(cacheSize) { @Override protected int sizeOf(String key, Bitmap bitmap) { if (bitmap != null) { return bitmap.getByteCount() / 1024; } return 0; } }; } @Override public int getCount() { return urls.get().size(); } @Override public Object getItem(int position) { return urls.get().get(position); } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { convertView = LayoutInflater.from(mContext.get()).inflate(R.layout.winelist_item, null); viewHolder = new ViewHolder(); viewHolder.im = (ImageView) convertView.findViewById(R.id.iv_winelist); viewHolder.tv = (TextView) convertView.findViewById(R.id.tv_winelist); convertView.setTag(viewHolder); } else { //view = convertView; viewHolder = (ViewHolder) convertView.getTag(); } String url = urls.get().get(position); viewHolder.im.setTag(url); viewHolder.tv.setText(names.get().get(position)); if (!viewHolder.im.getTag().equals(url)) { showImageView(viewHolder.im, url); } return convertView; } /** * 给ImageView设置Bitmap */ private void showImageView(ImageView imageView, String url) { // 先从cache中找bitmap缓存 Bitmap bitmap = get(url); if (url.equals("1")) { imageView.setImageBitmap(BitmapFactory.decodeResource(mContext.get().getResources(), R.mipmap.ic_launcher)); } else if (bitmap != null) { // 如果缓存命中 imageView.setImageBitmap(bitmap); } else { // 如果cache miss imageView.setImageBitmap(BitmapFactory.decodeResource(mContext.get().getResources(), R.mipmap.ic_launcher)); } } /** * 将Bitmap put 到 cache中 */ private void put(String key, Bitmap bitmap) { if (get(key) == null) { mLruCache.put(key, bitmap); } } /** * 在Cache中查找bitmap,如果miss则返回null */ private Bitmap get(String key) { return mLruCache.get(key); } /** * 从本地加载图片 */ private Bitmap loadBitmap(String urlStr) { Bitmap bitmap = null; File file = new File(urlStr); if (!file.exists()) { //Toast.makeText(mContext.get(), "文件损坏,请查看", Toast.LENGTH_SHORT).show(); Log.i("---LK---", "no file"); bitmap = BitmapFactory.decodeResource(mContext.get().getResources(), R.mipmap.ic_launcher); } else { bitmap = BitmapFactory.decodeFile(urlStr); } return bitmap; } /** * 加载可见项的图片 */ private void loadVisibleBitmap(int mFirstVisibleItem, int mVisibleItemCount) { for (int i = mFirstVisibleItem; i < mFirstVisibleItem + mVisibleItemCount; i++) { final String url = urls.get().get(i); Bitmap bitmap = get(url); ImageView mImageView; if (bitmap != null) { //缓存中存在该图片的话就设置给ImageView mImageView = (ImageView) mGridView.get().findViewWithTag(url); if (mImageView != null) { mImageView.setImageBitmap(bitmap); } } else { //不存在的话就开启一个异步线程去下载 ImageDownloadTask task = new ImageDownloadTask(this); mDownloadTaskList.add(task); task.execute(url); } } } /** * 取消所有的下载任务 */ public void cancelAllTask() { if (mDownloadTaskList != null) { for (int i = 0; i < mDownloadTaskList.size(); i++) { mDownloadTaskList.get(i).cancel(true); } } } /** * 从本地加载图片的异步task */ static class ImageDownloadTask extends AsyncTask<String, Void, Bitmap> { private String url; private WeakReference<WineListAdapter> photoAdapter; public ImageDownloadTask(WineListAdapter photoAdapter) { this.photoAdapter = new WeakReference<WineListAdapter>(photoAdapter); } @Override protected Bitmap doInBackground(String... params) { //在后台开始下载图片 url = params[0]; Bitmap bitmap = photoAdapter.get().loadBitmap(url); if (bitmap != null) { //把下载好的图片放入LruCache中 String key = url; photoAdapter.get().put(key, bitmap); } return bitmap; } @Override protected void onPostExecute(Bitmap bitmap) { super.onPostExecute(bitmap); //把下载好的图片显示出来 ImageView mImageView = (ImageView) photoAdapter.get().mGridView.get().findViewWithTag(url); if (mImageView != null && bitmap != null) { mImageView.setImageBitmap(bitmap); photoAdapter.get().mDownloadTaskList.remove(this);//把下载好的任务移除 } } } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { //GridView停止滑动时,去加载可见项的图片 if (scrollState == SCROLL_STATE_IDLE) { loadVisibleBitmap(mFirstVisibleIndex, mVisibleItemCount); } else { //GridView开始滑动时,取消所有加载任务 cancelAllTask(); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { mFirstVisibleIndex = firstVisibleItem; mVisibleItemCount = visibleItemCount; // 第一次打开,加载可见项 if (isFirstOpen && visibleItemCount > 0) { loadVisibleBitmap(mFirstVisibleIndex, mVisibleItemCount); isFirstOpen = false; } } private class ViewHolder { public ImageView im; public TextView tv; } }
相关文章推荐
- 解决viewpager加载本地1000多张图片oom问题
- 关于android gridview 加载大量图片的OOM问题解决方案
- Android相册解决加载大量图片卡顿问题
- android解决加载大图片卡顿和oom问题。
- 详解使用LruCache来解决图片OOM的问题
- 使用SurfaceView加载多张大分辨率图片做帧动画,解决OOM问题
- Android完美解决GridView异步加载图片和加载大量图片时出现Out Of Memory问题
- 使用Bitmap加载图片出现OOM问题
- 利用LruCache为GridView加载大量本地图片完整示例
- Android使用BitmapFactory.Options解决加载大图片内存溢出问题
- 安卓 使用LruCache 加载图片 遇到的问题
- Android Listview 加载图片优化--本地加载大量图片,解决滑动卡顿现象(滑动停止加载图片)
- 使用开源imageLoader优化listview加载大量本地图片的demo
- Android异步加载图片,解决图片过大OOM问题
- Android Listview 加载图片优化--本地加载大量图片,解决滑动卡顿现象(滑动停止加载图片)
- 转!Android使用BitmapFactory.Options解决加载大图片内存溢出问题
- 如何解决加载大图片时内存溢出的问题 OOM
- Android使用BitmapFactory.Options解决加载大图片内存溢出问题
- Windows Phone 用WebBrowser加载本地图片以及解决加载html页面出现乱码问题
- 使用ImageLoader+gallery加载图片导致图片哆嗦的问题解决办法