利用AsyncTask给ListView异步加载图片 实现图文混排
# AsyncTask
// 无参 无进度显示 有返回值
JSONObjectpublic class NewsTask extends AsyncTask {
private Activity activity;
private String url;
private OnTaskListener listener;
//构造方法 将 act 以及 url 传进来 listen实例化
public NewsTask (Activity activity, String url,OnTaskListener onTaskListener) {
this.activity = activity;
this.url = url;
this.listener = onTaskListener;
}
// 将 url 对应的json数据 转为 JSONObject
private JSONObject getJsonData(String url){
JSONObject jsonObject = null;
try {
// new URL(url).getConnection.getInputStream 合成
String jsonStr = readStream(new URL(url).openStream());
jsonObject = new JSONObject(jsonStr); //json字符串转为 json对象
} catch (IOException e) {
e.printStackTrace();
}catch (JSONException e) {
e.printStackTrace();
} return jsonObject;
}
// 转成 json 字符串
private String readStream (InputStream is){
InputStreamReader isr;
String result ="";
try {
String line = "";
// 通过定义字符集格式 将字节流 转为 字符流
isr = new InputStreamReader(is,"utf-8");
BufferedReader br = new BufferedReader(isr); // 缓存 策略 Buffer
while ((line = br.readLine()) != null){ // 逐行 读 直到为空
result += line;
}
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
// 子线程 任务
@Override
protected JSONObject doInBackground(Void... params) {
return getJsonData(url);
}
// execute后 doInBackground前 初始化
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(JSONObject jsonObject) {
super.onPostExecute(jsonObject);
if (jsonObject == null){
listener.onFailed("数据为空");
}else {
// 成功
listener.onSucceed(jsonObject);
}
// 注意释放
listener = null;
activity = null;
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
# act
new NewsTask(this, url, new OnTaskListener() {
@Override public void onSucceed(JSONObject jsonObject){
List beanList = new ArrayList();
JSONArray jsonArray = null;
// 操作数据
try {
jsonArray = jsonObject.getJSONArray("data");
for (int i=0;i beanList;
private LayoutInflater inflater;
private Context context;
private ImageThreadLoader imgLoader;
private int startIdx, endIdx;
public static String[] imgUrls; //创建静态数组
private boolean firstFlag;
public NewsAdapter(List beanList, Context context) {
this.beanList = beanList;
this.context = context;
inflater = LayoutInflater.from(context);
imgLoader = new ImageThreadLoader();
// 将所有 newsImgUrl 单独出来成为一个静态数组
imgUrls = new String[beanList.size()];
for (int i=0;i 0){
// 第一次 第一屏 加载 (此时 未主动滑动 且 totalItemCount不为0而且已经计算出来)
imgLoader.loadImages(startIdx,endIdx);
firstFlag = false;
}
}
// ViewHolder 内部类
private class HolderView{
private ImageView mImgView;
private TextView mTitle,mContent;
}
# Thread
public class ImageThreadLoader {
private ImageView mImageView;
private String mUrl;
// Lru(least recently used近期最少使用 算法) LruCache是Android基于LRU封装的缓存 (类型类似于map)
private LruCache mCache;
private ListView mListView;
private Set mVisiableTasks;
// 匿名Handler 处理子线程和主线程的消息传递 更新UI
private Handler mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
// url 一一对应ImgView 避免 多次赋值 以及 赋值混乱
if (mImageView.getTag() == mUrl){
mImageView.setImageBitmap((Bitmap) msg.obj);
}
}
};
public void getImageByThrea(ImageView imgView, final String imgUrl){
// 存储 imgView 和 url
mImageView = imgView;
mUrl = imgUrl;
//
new Thread(){
@Override
public void run() {
super.run();
Bitmap bitmap = getBitmapBy(imgUrl);
Message msg = new Message();
msg.obj = bitmap;
mHandler.sendMessage(msg); //发送消息
}
}.start();
}
private Bitmap getBitmapBy(String imgUrl) {
Bitmap bitmap = null;
InputStream is = null;
URL url = null;
try {
url = new URL(imgUrl);
} catch (MalformedURLException e) {
e.printStackTrace();
}
HttpURLConnection connection = null;
try {
connection = (HttpURLConnection) url.openConnection();
} catch (IOException e) {
e.printStackTrace();
}
try {
is = connection.getInputStream();
} catch (IOException e) { e.printStackTrace(); }
BufferedInputStream bis = new BufferedInputStream(is);
bitmap = BitmapFactory.decodeStream(bis);
return bitmap;
}
// 构造方法 外界 实例化ImageThreadLoader的成员变量 保证只有一个 LruCache对象
public ImageThreadLoader() {
mListView = listView;
// 初始化 集合
mVisiableTasks = new HashSet<>();
// 获得当前 最大可以内存
int maxSize = (int) Runtime.getRuntime().maxMemory();
// 分多少内存给缓存
int cacheSize = maxSize / 4;
// 实例化
mCache = new LruCache(cacheSize){
// 必须实现的方法 返回每次存入时 key 对应的value的大小
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();
}
};
}
private void addToCache(String key,Bitmap value){
if (getFromCache(key) == null){
// 内存中不存在
mCache.put(key,value);
}
}
private Bitmap getFromCache(String key){
return mCache.get(key);
}
// AsyncTask方式
public void setImageByAsyncTask(ImageView imgView,String url){
mImageView = imgView;
mUrl = url;
// 先从缓存中取数据
Bitmap bitmap = getFromCache(url);
if (bitmap == null){
// 没有缓存 下载
new ImageAsycTask().execute(url);
}else {
imgView.setImageBitmap(bitmap);
}
}
// 加载序列中 指定的所有图片
public void loadImages(int startIdx,int endIdx){
for (int i=startIdx;i{
private String taskImgUrl;
public ImageAsycTask(String taskImgUrl) {
this.taskImgUrl = taskImgUrl;
}
@Override
protected Bitmap doInBackground(String... params) {
String url = params[0];
Bitmap bitmap = getBitmapBy(url);
if (bitmap != null){
// 加入到缓存
addToCache(url,bitmap);
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
ImageView imgView = (ImageView) mListView.findViewWithTag(taskImgUrl);
if (imgView != null && bitmap != null){
imgView.setImageBitmap(bitmap);
}
mVisiableTasks.remove(this);
}
}
}
# 接口
public interface OnTaskListener {
// 将Task独立出来以及 定义接口和将返回值 定义成 JSONObject 都是为了封装
public void onSucceed(JSONObject jsonObject);
public void onFailed(String msg);
}
链接
AsyncTask源码分析
知乎