android 自定义控件之NetWorkImageView 处理listview等控件中的图片加载乱序问题
0.调用:
BaseAdapter中设置方法 holder.iv.loadImage(url);
adapter_xxx.xml 中 控件需要用 xxx.NetWorkImageView
1 NetWorkImageView.java 和 异步加载图片的代码 AsyncImageLoader.java
import com.example.textimage.AsyncImageLoader.ImageLoadCallback; import android.app.Activity; import android.content.Context; import android.graphics.drawable.Drawable; import android.text.TextUtils; import android.util.AttributeSet; import android.util.Log; import android.widget.ImageView; /** * 自定义加载网络图片ImageView * * @author mrljdx * https://github.com/mrljdx/LoadImageView/tree/master/src/com/mrljdx * /loadimage * */ public class NetWorkImageView extends ImageView { private final static String TAG = "NetWorkImageView"; private static AsyncImageLoader asyncImageLoader; private Context context; public NetWorkImageView(Context context) { this(context, null); } public NetWorkImageView(Context context, AttributeSet attrs) { this(context, attrs, 0); } public NetWorkImageView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); initSth(context); } private void initSth(Context context) { this.context = context; if (asyncImageLoader == null) { asyncImageLoader = new AsyncImageLoader(context); } } public void loadImage(String imgUrl, final int defaultRes) { if (TextUtils.isEmpty(imgUrl)) { setImageResource(defaultRes);// 调用ImageView中默认的设置图片方法 return; } Log.d(TAG, "load imgUrl is :" + imgUrl); Drawable d = asyncImageLoader.loadDrawable(imgUrl, new ImageLoadCallback() { @Override public void imageLoaded(Drawable drawable, String imgUrl) { Object tag = getTag(); // 获取NetWorkImageView设置的Tag值,比对如果有则不再重新加载 if (tag != null && (tag instanceof String) && !tag.toString().equals(imgUrl)) { return; } if (context instanceof Activity) { // 如果当前Activity被结束了,则不加载图片 if (((Activity) context).isFinishing()) { return; } } // 设置显示图片 setImage(drawable, defaultRes); } }); setImage(d, defaultRes); } // 显示图片 private void setImage(Drawable drawable, int defaultRes) { if (drawable != null) { setImageDrawable(drawable); return; } if (defaultRes != -1) { setImageResource(defaultRes); } } public void loadImage(String imgUrl) { loadImage(imgUrl, -1); } /** * 取消加载图片 */ public void cancelTask() { asyncImageLoader.shutDownTread(); } }
import java.io.BufferedInputStream; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.lang.ref.SoftReference; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.PixelFormat; import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.os.Environment; import android.os.Handler; import android.os.Message; import android.text.TextUtils; import android.util.Log; /** * 异步网络请求图片加载类 * * @author mrljdx * */ public class AsyncImageLoader { final static String TAG = "AsyncImageLoader"; /** /sdcard/Android/data/%package_name%/files/images */ private static File PIC_PATH; private static HashMap<String, SoftReference<Drawable>> picCache; private BitmapFactory.Options opts = new BitmapFactory.Options(); private ExecutorService excutorsService = Executors.newFixedThreadPool(1); private int width; private int height; private Context mContext; public AsyncImageLoader(Context context) { this.mContext = context; int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024); Log.d(TAG, "Max memory is " + maxMemory + "M"); PIC_PATH = new File(mContext.getExternalFilesDir("images") + File.separator); picCache = new HashMap<String, SoftReference<Drawable>>(); opts.inSampleSize = 1; opts.inPreferredConfig = Bitmap.Config.ARGB_8888; } public void setThreads(int num) { this.excutorsService = Executors.newFixedThreadPool(num); } public interface ImageLoadCallback { public void imageLoaded(Drawable drawable, String imgUrl); } // 加载图片 public Drawable loadDrawable(final String imgUrl, final ImageLoadCallback mCallback) { if (TextUtils.isEmpty(imgUrl)) { return null; } // 获取图片文件名称 final String fileName = imgUrl.substring(imgUrl.lastIndexOf("/") + 1); final String imgUrlHashCode = imgUrl.hashCode() + ""; // 如果有缓存则返回图片 if (picCache.containsKey(imgUrlHashCode)) { Drawable imgDrawable = picCache.get(imgUrlHashCode).get(); if (imgDrawable != null) { return imgDrawable; } } final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { mCallback.imageLoaded((Drawable) msg.obj, imgUrl); } }; excutorsService.submit(new Runnable() { @Override public void run() { Drawable drawable = loadImageFromUrl(imgUrl, fileName); if (drawable != null) {// 获取到图片 if (width != 0) { try { drawable = zoomDrawable(drawable, width, height, fileName); } catch (Exception e) { e.printStackTrace(); } width = 0; height = 0; } picCache.put(imgUrlHashCode, new SoftReference<Drawable>( drawable)); } handler.sendMessage(handler.obtainMessage(0, drawable)); } }); return null; } // 通过网络请求获取图片 public Drawable loadImageFromUrl(String imgUrl, String fileName) { if (TextUtils.isEmpty(imgUrl)) { return null; } Drawable drawable = null; fileName = String.valueOf(fileName.hashCode()); // 将文件名hash if (!PIC_PATH.exists()) {// 判断存放图片的文件夹是否存在 PIC_PATH.mkdirs();// 不存在则创建一个图片文件夹 } File imgFile = new File(PIC_PATH, fileName); if (imgFile.exists()) {// 如果存在在SD卡中,则返回SD卡里的图片 try { drawable = getDrawableFromSdcard(fileName); } catch (OutOfMemoryError outOfMemoryError) { outOfMemoryError.printStackTrace(); return null; } return getDrawableFromSdcard(fileName); } else {// 如果内存和SD卡都不存在则网络请求图片 URL url; BufferedInputStream inputStream = null; HttpURLConnection con = null; try { Log.d(TAG, "load imgUrl is:" + imgUrl); url = new URL(imgUrl); con = (HttpURLConnection) url.openConnection(); con.setConnectTimeout(15000);// 设置网络请求超时时间15秒 con.setReadTimeout(15000); con.connect(); InputStream is = con.getInputStream(); // 获取图片流 inputStream = new BufferedInputStream(is); // 赋值 saveImage(imgFile, inputStream); // 保存图片到本地SD卡 is.close();// 关闭输入流 // String imgCookie = con.getHeaderField(pos); } catch (FileNotFoundException e) { e.printStackTrace(); return null; } catch (MalformedURLException e1) { e1.printStackTrace(); return null; } catch (IOException e) { e.printStackTrace(); return null; } catch (Exception e) { e.printStackTrace(); return null; } finally { if (con != null) { con.disconnect(); } if (inputStream != null) try { inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } return drawable; } // 从本地SD卡获取图片 private Drawable getDrawableFromSdcard(String fileName) { Bitmap source = BitmapFactory.decodeFile(PIC_PATH + File.separator + fileName, opts); if (source == null) { return null; } else { return new BitmapDrawable(source); } } // 保存图片到本地SD卡 private void saveImage(File image, BufferedInputStream bis) { if (image != null && image.getParentFile() != null) { image.getParentFile().mkdirs(); } FileOutputStream fos = null; // 定义文件输出流 int BUFFER_SIZE = 1024; byte[] buf = new byte[BUFFER_SIZE]; int size = 0; try { fos = new FileOutputStream(image); while ((size = bis.read(buf)) != -1) { fos.write(buf, 0, size); } ; fos.close(); bis.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } } // 取消所有正在执行的任务 public void shutDownTread() { excutorsService.shutdownNow(); } // 处理图片 private Drawable zoomDrawable(Drawable drawable, int w, int h, String fileName) { // 取图片的真实大小 int intrinsicw = drawable.getIntrinsicWidth(); int intrinsich = drawable.getIntrinsicHeight(); // 设置为true,表示解析Bitmap对象,该对象不占内存 opts.inJustDecodeBounds = true; BitmapFactory.decodeFile(PIC_PATH + File.separator + fileName, opts); // 设置为false,解析Bitmap对象加入到内存中 opts.inJustDecodeBounds = false; int width = opts.outWidth; int height = opts.outHeight; drawable.setBounds(0, 0, width, height); int minW = Math.min(width, w); int minH = Math.min(height, h); float scaleWidth = ((float) w / intrinsicw); float scaleHeight = ((float) h / intrinsich); Matrix matrix = new Matrix(); if (minW == width && minH == height) { scaleWidth = scaleHeight = mContext.getResources() .getDisplayMetrics().density; } else if (minW == width && minH == h) { scaleWidth = scaleHeight; } else if (minW == w && minH == height) { scaleHeight = scaleWidth; } else { scaleWidth = scaleHeight = Math.min(scaleWidth, scaleHeight); } Bitmap oldbmp = drawableToBitmap(drawable, width, height); matrix.postScale(scaleWidth, scaleHeight); Bitmap newbmp = Bitmap.createBitmap(oldbmp, 0, 0, width, height, matrix, true); return new BitmapDrawable(null, newbmp); } // Drawable To Bitmap private Bitmap drawableToBitmap(Drawable drawable, int width, int height) { Bitmap.Config config = drawable.getOpacity() != PixelFormat.OPAQUE ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565; Bitmap bitmap = Bitmap.createBitmap(width, height, config); Canvas canvas = new Canvas(bitmap); drawable.setBounds(0, 0, width, height); drawable.draw(canvas); return bitmap; } }