利用AsyncTask给ListView异步加载图片 实现图文混排
# AsyncTask
// 无参 无进度显示 有返回值
JSONObjectpublic class NewsTask extends AsyncTask<Void,Void,JSONObject> {
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<NewsBean> beanList = new ArrayList<NewsBean>();
JSONArray jsonArray = null;
// 操作数据
try {
jsonArray = jsonObject.getJSONArray("data");
for (int i=0;i<jsonArray.length();i++){
JSONObject object = (JSONObject) jsonArray.get(i);
NewsBean bean = new NewsBean();
bean.newsImgUrl = object.getString("picBig");
bean.newsTitle = object.getString("name");
bean.newsContent = object.getString("description");
beanList.add(bean);
}
// adapter 将 listView 与 数据绑定
listView.setAdapter(new NewsAdapter(beanList,MainActivity.this,listView));
} catch (JSONException e) {
e.printStackTrace();
}
}
@Override public void onFailed(String msg) {
}
}).execute();
# BaseAdapter
public class NewsAdapter extends BaseAdapter implements AbsListView.OnScrollListener{
private List<NewsBean> beanList;
private LayoutInflater inflater;
private Context context;
private ImageThreadLoader imgLoader;
private int startIdx, endIdx;
public static String[] imgUrls; //创建静态数组
private boolean firstFlag;
public NewsAdapter(List<NewsBean> 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<beanList.size();i++){
imgUrls[i] = beanList.get(i).newsImgUrl;
}
listView.setOnScrollListener(this);
firstFlag = true; // 首次加载
}
@Override
public int getCount() {
return beanList.size();
}
@Override
public Object getItem(int position) {
return beanList.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
HolderView holderView;
if (convertView == null){
holderView = new HolderView();
convertView = inflater.inflate(R.layout.item_layout,null);
holderView.mImgView = (ImageView) convertView.findViewById(R.id.imgView);
holderView.mTitle = (TextView) convertView.findViewById(R.id.tv_title);
holderView.mContent = (TextView) convertView.findViewById(R.id.tv_content);
convertView.setTag(holderView); //绑定
}else{
holderView = (HolderView) convertView.getTag();
}
// 赋值
NewsBean bean = beanList.get(position);
holderView.mImgView.setImageResource(R.mipmap.ic_launcher);
// 绑定
holderView.mImgView.setTag(bean.newsImgUrl);
// 多线程
// new ImageThreadLoader().getImageByThrea(holderView.mImgView,bean.newsImgUrl);
// AsyncTask 方式 依次执行任务
// new ImageThreadLoader().setImageByAsyncTask(holderView.mImgView,bean.newsImgUrl);
// 使用LruCache 以内存换效率
// imgLoader.setImageByAsyncTask(holderView.mImgView,bean.newsImgUrl);
holderView.mTitle.setText(bean.newsTitle);
holderView.mContent.setText(bean.newsContent);
}
// AbsListView.OnScrollListener 滑动监听
@Overridepublic
void onScrollStateChanged(AbsListView view, int scrollState) {
// 状态改变
if (scrollState == SCROLL_STATE_IDLE){
// 滚动停止 加载数据
imgLoader.loadImages(startIdx,endIdx);
}else {
// 停止后台线程 保证滚动的流畅
imgLoader.cancleAllTasks();
}
}
// onScroll 一开始就会执行
@Overridepublic
void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
startIdx = firstVisibleItem; // 第一个可见项
endIdx = firstVisibleItem + visibleItemCount; // 最后一个可见项
if (firstFlag && totalItemCount > 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<String,Bitmap> mCache;
private ListView mListView;
private Set<ImageAsycTask> 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<String, Bitmap>(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<endIdx;i++){
String url = NewsAdapter.imgUrls[i];
// 先从缓存中取数据
Bitmap bitmap = getFromCache(url);
if (bitmap == null){
// 没有缓存 下载
ImageAsycTask task = new ImageAsycTask(url);
task.execute(url);
mVisiableTasks.add(task); // 加到Set集合中
}else {
// listView 根据 tag 找到url对应的ImgView
ImageView imgView = (ImageView) mListView.findViewWithTag(url);
imgView.setImageBitmap(bitmap);
}
}
}
public void cancleAllTasks(){
if (mVisiableTasks != null){
for (ImageAsycTask task : mVisiableTasks) {
task.cancel(true);
}
}
}
private class ImageAsycTask extends AsyncTask<String,Void,Bitmap>{
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);
}