自定义加载网络图片工具: 三级缓存 解决图片显示错位的问题
2016-07-15 16:40
766 查看
自定义加载网络图片工具: 三级缓存
该类中主要是在 请求网络加载图片之前设置一个,可以理解为listview的条目请求网络的位置,然后在请求网络的方法中展示图片之前 设置一个 显示在屏幕上位置 判断二者是否相等,如果相等就直接显示图片public class MyBitmapUtils { private final Context context; private LruCache<String, Bitmap> mLruCache; // key 代表 url地址, value 代表显示的图片 private File rootFile; //本地缓存的根目录 private ExecutorService mExecutorService; //线程池 public MyBitmapUtils(Context context) { this.context = context; // maxMemory : mLruCache能管理的最大内存 int maxMemory = (int) Runtime.getRuntime().maxMemory(); int cacheSize = maxMemory / 8; mLruCache = new LruCache<String, Bitmap>(cacheSize) { /** * 表示当前存储的对象, * @param key * @param bitmap * @return */ @Override protected int sizeOf(String key, Bitmap bitmap) { return bitmap.getRowBytes() * bitmap.getHeight(); //每一行的字节个数*高度 = bitmap的大小 } }; //本地缓存的路径 /data/data rootFile = context.getFilesDir(); //创建线程池的实例化对象 创建固定大小的线程池 内部维护了4个线程 mExecutorService = Executors.newFixedThreadPool(4); } /** * 展示网络图片 * * @param image 展示的图片 * @param imageUrl 图片的url地址 */ public void display(ImageView image, String imageUrl) { //1 .从内存中获取图片 Bitmap cacheBitmap = mLruCache.get(imageUrl); if (cacheBitmap != null) { image.setImageBitmap(cacheBitmap); Log.d("MyBitmapUtils", "--从内存中获取"); return; //表示能从内存获取到,就直接展示了.不再继续往下执行 } //2.从本地获取图片 String imageName = MD5Encoder.encode(imageUrl);// url+Md5加密 File cacheFile = new File(rootFile, imageName); if (cacheFile.exists() && cacheFile.length() > 0) { // 加载到内存中 Bitmap decodeFileBitmap = BitmapFactory.decodeFile(cacheFile.getAbsolutePath()); mLruCache.put(imageUrl, decodeFileBitmap); image.setImageBitmap(decodeFileBitmap); Log.d("MyBitmapUtils", "--从本地获取"); return; } /** * 在请求网络之前 背上一个 标记 tag */ int position = (int) image.getTag(); //可以理解为 请求的位置 //3. 从网络中获取 需要开启子线程去加载图片 mExecutorService.execute(new DownloadRunnable(image, imageUrl, position)); Log.d("MyBitmapUtils", "--从网络获取"); } private class DownloadRunnable implements Runnable { private final String imageUrl; private final ImageView image; private final int position; /** * @param image * @param imageUrl * @param position 为了解决 listview加载图片显示错乱的问题 该处的 position 可以理解为 请求时候的位置 */ public DownloadRunnable(ImageView image, String imageUrl, int position) { this.position = position; this.image = image; this.imageUrl = imageUrl; } @Override public void run() { Bitmap bitmap = null; HttpURLConnection urlConnection = null; try { URL url = new URL(imageUrl); urlConnection = (HttpURLConnection) url.openConnection(); urlConnection.setConnectTimeout(20 * 1000); urlConnection.setReadTimeout(10 * 1000); //获取响应码 int responseCode = urlConnection.getResponseCode(); if (responseCode == 200) { InputStream is = urlConnection.getInputStream(); bitmap = BitmapFactory.decodeStream(is); //保存到内存中 mLruCache.put(imageUrl, bitmap); //保存到本地 (bitmap 如何转换成本地图片) /** * compress : 压缩图片 * format : 压缩的格式 * quality : 压缩质量 范围 0--100 0,不压缩; 100,完全压缩 * OutputStream stream 输出流 写到本地 */ File cacheFile = new File(rootFile, MD5Encoder.encode(imageUrl)); OutputStream out = new FileOutputStream(cacheFile); bitmap.compress(Bitmap.CompressFormat.PNG, 100, out); //展示图片 //获取上下文对象 MainActivity mainActivity = (MainActivity) context; final Bitmap finalBitmap = bitmap; mainActivity.runOnUiThread(new Runnable() { //使用 runOnUiThread 从子线程切换到主线程 @Override public void run() { int currentPos = (int) image.getTag(); //请求的位置 如果等于 显示在屏幕上的位置 就显示图片 if (position==currentPos){ image.setImageBitmap(finalBitmap); } } }); } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } finally { if (urlConnection != null) { urlConnection.disconnect(); } } } } }
该类中是 在显示图片之前设置一个 tag viewHolder.image.setTag(position);
/** * 自定义 Adapter */ public class ImgAdapter extends ArrayAdapter<String> { private final MyBitmapUtils mBitmapUtils; public ImgAdapter(Context context, int resource, String[] objects) { super(context, resource, objects); mBitmapUtils = new MyBitmapUtils(context); } @Override public View getView(int position, View convertView, ViewGroup parent) { String url = getItem(position); //根据当前的位置获取到图片的URL地址 ViewHolder viewHolder = null; if (convertView == null) { viewHolder = new ViewHolder(); convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_image, null); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } viewHolder.image = (ImageView) convertView.findViewById(R.id.image); //为了解决图片显示错位乱跳的问题 我们这里处理的方法是 为 image 绑定一个 tag viewHolder.image.setTag(position); mBitmapUtils.display(viewHolder.image, url); return convertView; } public class ViewHolder { ImageView image; } }
主界面
public class MainActivity extends AppCompatActivity { ListView listView; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); listView = (ListView) findViewById(R.id.list_view); ImgAdapter adapter = new ImgAdapter(this, 0, ImageId.imageUrl); listView.setAdapter(adapter); } }
MD5 加密的工具类
package com.gaoo.listviewtest; import java.security.MessageDigest; public class MD5Encoder { public static String encode(String string) { try { byte[] hash = MessageDigest.getInstance("MD5").digest(string.getBytes("UTF-8")); StringBuilder hex = new StringBuilder(hash.length * 2); for (byte b : hash) { if ((b & 0xFF) < 0x10) { hex.append("0"); } hex.append(Integer.toHexString(b & 0xFF)); } return hex.toString(); } catch (Exception e) { e.printStackTrace(); } return null; } }
另外记得在清单文件中加上权限
<uses-permission android:name="android.permission.INTERNET" />
相关文章推荐
- 完美实现Android ListView中的TextView的跑马灯效果
- android上改变listView的选中颜色
- 按右键另存图片只能存BMP
- photoshop去除图片上的水印
- Delphi7中Listview的常用功能汇总
- Delphi控件ListView的属性及使用方法详解
- upload上传单张图片
- 图片引发的溢出危机(图)
- C# WinForm控件对透明图片重叠时出现图片不透明的简单解决方法
- C#实现把彩色图片灰度化代码分享
- C#将图片和字节流互相转换并显示到页面上
- C#监控文件夹并自动给图片文件打水印的方法
- 纯CSS实现的当鼠标移上图片添加阴影效果代码
- 如何使用C#从word文档中提取图片
- C#实现打开画图的同时载入图片、最大化显示画图窗体的方法
- C#图片添加水印的实现代码
- 随鼠标移动的图片或文字特效代码
- CSS 图片横向排列实现代码
- C#实现将Email地址转成图片显示的方法
- C#实现图片加相框的方法