Android ListView,GridView,RecyclerView图片加载错位闪动问题解决办法
2016-04-12 13:43
921 查看
最近看了一下RecyclerView这个控件,的确非常好用,但是也并没有摆脱这种问题,recyclerview内部好像自带有控件的复用。
问题的根源还是控件的复用以及异步加载所引起的问题
解决思路:
1.使用缓存,从缓存中加载的速度大大少于从网络加载
2.设置默认图片,当一个item设置个图片然后被复用,而当前显示的图片还没有数据,正在从网络获取,这个时候此item就会显示复用前显示的图片,而当前应该显示的图片从网络中获取到之后就会重新加载上去就出现的图片闪动的情况
3.给ImageView设置TAG
我封装了一个类来进行网络获取加载图片,代码比较简单,用起来也非常方便,诸位可以根据自己的需求进行修改
话不多说上代码:
另外还有一些上文中用到的方法
问题的根源还是控件的复用以及异步加载所引起的问题
解决思路:
1.使用缓存,从缓存中加载的速度大大少于从网络加载
2.设置默认图片,当一个item设置个图片然后被复用,而当前显示的图片还没有数据,正在从网络获取,这个时候此item就会显示复用前显示的图片,而当前应该显示的图片从网络中获取到之后就会重新加载上去就出现的图片闪动的情况
3.给ImageView设置TAG
我封装了一个类来进行网络获取加载图片,代码比较简单,用起来也非常方便,诸位可以根据自己的需求进行修改
话不多说上代码:
package My.Utils; import android.content.Context; import android.graphics.Bitmap; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.util.Log; import android.util.LruCache; import android.widget.ImageView; import com.wkk.myutils.R; import java.io.IOException; /** * 4000 Created by Think on 2016/4/11. */ public class ImageLoader { private static My.Utils.ImageLoader ImageLoader; private LruCache<String, Bitmap> lruCache; public static final int ID = -100; private boolean Savedlocal = false;//此属性控制是否需要缓存到本地 private Context context; @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR1) private ImageLoader(Context context) { this.context = context; // 版本低于12 数量 大于等于12 容量 if (Build.VERSION.SDK_INT < 12) { lruCache = new LruCache<String, Bitmap>(100); } else { lruCache = new LruCache<String, Bitmap>(5 * 1024 * 1024) { @Override protected int sizeOf(String key, Bitmap value) { return value.getByteCount(); } }; } } public static My.Utils.ImageLoader getInstance(Context context) { if (ImageLoader == null) { ImageLoader = new ImageLoader(context); } return ImageLoader; } /** * 对外开放方法 * 1.需要设置的Imageview * 2.图片的URl * 3.默认图片 */ public void setimage(ImageView image, String url, int resid) { image.setTag(url); Bitmap bitmap = lruCache.get(url); if (bitmap != null) { image.setImageBitmap(bitmap); return; } else if (Savedlocal) { bitmap = Utils.getSavePhone(url);//setSaveToPhone if (bitmap != null) { image.setImageBitmap(bitmap); return; } } if (resid != ID) { image.setImageResource(resid); } else { image.setImageResource(R.mipmap.ic_launcher); } new AsyncImageDown().execute(new Image(url, image, null)); } public void setimage(ImageView image, String url, Bitmap bitmap1) { image.setTag(url); Bitmap bitmap = lruCache.get(url); if (bitmap != null) { image.setImageBitmap(bitmap); return; } else if (Savedlocal) { bitmap = Utils.getSavePhone(url);//setSaveToPhone if (bitmap != null) { image.setImageBitmap(bitmap); return; } } if (bitmap1 != null) { image.setImageBitmap(bitmap1); } else { image.setImageResource(R.mipmap.ic_launcher); } new AsyncImageDown().execute(new Image(url, image, null)); } public void setimage(ImageView image, String url, Drawable drawable) { image.setTag(url); Bitmap bitmap = lruCache.get(url); if (bitmap != null) { image.setImageBitmap(bitmap); return; } else if (Savedlocal) { bitmap = Utils.getSavePhone(url);//setSaveToPhone if (bitmap != null) { image.setImageBitmap(bitmap); return; } } if (drawable != null) { image.setImageDrawable(drawable); } else { image.setImageResource(R.mipmap.ic_launcher); } new AsyncImageDown().execute(new Image(url, image, null)); } /** * 清空数据缓存 */ public void evictAll() { lruCache.evictAll(); } private class AsyncImageDown extends AsyncTask<Image, Void, Image> { @Override protected Image doInBackground(Image... images) { //url imaeg Image image = images[0]; try { Bitmap bitmap = HttpUtils.getImageFromNet(image.getUrl()); if (bitmap != null && image.getUrl() != null) { lruCache.put(image.getUrl(), bitmap); if (Savedlocal) { Utils.setSaveToPhone(image.getUrl(), bitmap); } image.setBitmap(bitmap); return image; } } catch (IOException e) { e.printStackTrace(); Log.d("测试", "ImageLoader+AsyncImageDown+doInBackground+图片请求出错" + e.toString()); } return null; } @Override protected void onPostExecute(Image image) { if (image != null && image.getBitmap() != null && image.getUrl().equalsIgnoreCase((String) image.getImageView().getTag())) { image.getImageView().setImageBitmap(image.getBitmap()); } } } public void setSavedlocal(boolean savedlocal) { Savedlocal = savedlocal; } private class Image { private String url; private ImageView imageView; private Bitmap bitmap; public Image(String url, ImageView imageView, Bitmap bitmap) { this.url = url; this.imageView = imageView; this.bitmap = bitmap; } public Bitmap getBitmap() { return bitmap; } public void setBitmap(Bitmap bitmap) { this.bitmap = bitmap; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public ImageView getImageView() { return imageView; } public void setImageView(ImageView imageView) { this.imageView = imageView; } } }
另外还有一些上文中用到的方法
/** * 保存图片到手机内存 * * @param filename * @param bitmap * @return */ public static void setSaveToPhone(String filename, Bitmap bitmap) { filename = filename.replace("/", ""); String path = getPath() + "/" + filename; File file = new File(path); if (!file.exists()) { try { file.createNewFile(); } catch (IOException e) { e.printStackTrace(); } } try { ByteArrayOutputStream baos = new ByteArrayOutputStream(); bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos); byte[] bytes = baos.toByteArray(); FileOutputStream out = new FileOutputStream(path); out.write(bytes); out.flush(); out.close(); baos.close(); } catch (Exception e) { i(e.toString() + "utils-保存图片到手机内存-保存出错"); } } /** * 从本地读取图片 */ public static Bitmap getSavePhone(String filename) { filename = filename.replace("/", ""); String path = getPath() + "/" + filename; try { FileInputStream in = new FileInputStream(path); Bitmap bitmap = BitmapFactory.decodeStream(in); in.close(); return bitmap; } catch (Exception e) { } return null; } public static String getPath() { File file = new File(Environment.getExternalStorageDirectory().getPath() + "/wkk"); if (!file.exists() || !file.isDirectory()) { file.mkdirs(); } return file.getPath(); } /** * 根据url连接网络 获取图片 * * @param url * @return * @throws IOException */ public static Bitmap getImageFromNet(String url) throws IOException { HttpURLConnection conn = null; URL mURL = new URL(url);// 创建一个ur对象 // 得到http的链接对象 conn = (HttpURLConnection) mURL.openConnection(); conn.setRequestMethod("GET");// 设置请求的方法为Get conn.setConnectTimeout(10000);// 设置链接服务器的超时时间 如果超过10秒钟没有链接 抛异常 conn.setReadTimeout(10000);// 设置读取数据超时时间 conn.connect();// 开始链接 int responseCode = conn.getResponseCode();// 得到服务器相应码 if (responseCode == 200) { // 访问成功 InputStream is = conn.getInputStream();// 获得服务器返回的流 Bitmap bitmap = BitmapFactory.decodeStream(is);// 根据流创建一个Bitmap位图对象 is.close(); return bitmap; } else { Utils.d("测试", "访问失败:responseCode=" + responseCode); } retur ace9 n null; }
相关文章推荐
- Android设置系统开机自动永不休眠
- 关于Android开发的40条优化建议
- Android progressBar 自定义
- AndroidManifest.xml文件反编译
- android:省市二级联动下拉框
- Android ContentProvider详解
- Android TabLayout与ViewPager实现动态Tab
- Android Studio的相关设置信息笔记
- Android TV开发 焦点返回ListView时, 返回到离开时的位置
- 关于android:background="@drawable/bg_product_detail_item_normal"的理解
- Android V7包学习笔记更新中.....
- [Android] envsetup.sh及lunch是什么玩艺尔
- 别再抱怨了,国内这么多优秀的Android资源你都知道吗?(转)
- Android Studio 入门(转)
- android RelativeLayout 内容居中解决办法
- 关于新建Android Studio项目时默认的编译sdk版本导致的兼容问题
- Android RelativeLayout各个属性的含义
- Android Studio2.0 安卓开发者不得不知的功能
- android开发 华为 点击跳转到权限管理页面
- Android_实现星星控件_学习