本来打算增加支持本地缓存以加速图片加载速度,以及支持默认图片还有图片加载失败图片显示等功能,由于本人懒,所以搁置!
图片缓存可以参考:Android--简单的图片三级缓存工具类
因为都是测试时用的,所以功能写的很简单也不完善,仅供参考!
直接上代码:
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class RemoteImageView extends androidx.appcompat.widget.AppCompatImageView {
// 整个RemoteImageView通用的线程池
public static final ExecutorService executor = Executors.newFixedThreadPool(5);
public static final int MSG_LOAD_SUCCESS = 0x20;
public static final int MSG_LOAD_FAIL = 0x21;
private String imgUri;
private Bitmap bitmap;
// 标识当前正在加载的图片是否已经失效,失效就直接取消下载或回收Bitmap,防止在ListView中出现图片错乱
private volatile boolean isInvalid;
private AsynCallBack callBack = new AsynCallBack() {
@Override
public void success(Object obj) {
Message msg = mHandler.obtainMessage();
msg.what = MSG_LOAD_SUCCESS;
msg.obj = obj;
mHandler.sendMessage(msg);
}
@Override
public void fail() {
Message msg = mHandler.obtainMessage();
msg.what = MSG_LOAD_FAIL;
mHandler.sendMessage(msg);
}
};
private static final Handler mHandler = new Handler() {
@Override
public void handleMessage(@NonNull Message msg) {
switch (msg.what) {
case MSG_LOAD_SUCCESS:
RemoteImageView remoteImageView = (RemoteImageView) msg.obj;
remoteImageView.setImageBitmap(remoteImageView.bitmap);
break;
case MSG_LOAD_FAIL:
// TODO
break;
}
}
};
public RemoteImageView(Context context) {
super(context);
}
public RemoteImageView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
}
public RemoteImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public void setRemoteUri(String uri) {
if (imgUri == null) {
imgUri = uri.trim();
} else if (imgUri.equalsIgnoreCase(uri.trim())) {
return;
} else {
invalid();
}
isInvalid = false;
loadRemoteImage(uri, callBack);
}
/**
* 回收Bitmap资源
*/
private void recycle() {
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
}
bitmap = null;
}
// 判断当前正在加载的图片是否已经无效
// 比如:在拖动ListView时,如果当前ImageView的连接会重新设置了(跟原来的不一样了),
// 那么就把当前正在下载或者使用的资源关闭掉,并重新开始下载图片。
// 这样就防止了图片显示混乱的问题!!!
private void invalid() {
isInvalid = true;
setImageBitmap(null);
recycle();
}
private void loadRemoteImage(final String uri, final AsynCallBack callBack) {
executor.submit(new Runnable() {
@Override
public void run() {
try {
// 如果当前失效了,那么直接返回
if(isInvalid) {
return;
}
byte[] data = getDataFromHttp(uri);
if (data == null && !isInvalid) {
if (callBack != null) {
callBack.fail();
}
return;
}
RemoteImageView.this.bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
if (callBack != null&& !isInvalid) {
callBack.success(RemoteImageView.this);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
private byte[] getDataFromHttp(String path) throws Exception {
URL url = new URL(path);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setConnectTimeout(6000);
conn.setRequestMethod("GET");
if (conn.getResponseCode() != 200) {
throw new RuntimeException("请求url失败:" + path);
}
InputStream is = conn.getInputStream();
byte[] data = read(is);
return data;
}
private byte[] read(InputStream is) throws IOException {
if (is == null) {
throw new RuntimeException("InputStream must not null!");
}
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buff = new byte[2048];
int len = 0;
while (((len = is.read(buff)) != -1) && !isInvalid) {
bos.write(buff, 0, len);
}
is.close();
return isInvalid ? null : bos.toByteArray();
}
interface AsynCallBack {
void success(Object obj);
void fail();
}
}