android 自定义控件之NetWorkImageView 处理listview等控件中的图片加载乱序问题

时间:2023-03-09 13:31:56
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;
}
}