Android - AsyncTask (SDK 24)

利用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);
}

链接

AsyncTask源码分析

知乎

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 151,688评论 1 330
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 64,559评论 1 273
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 101,749评论 0 226
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 42,581评论 0 191
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 50,741评论 3 271
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 39,684评论 1 192
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,122评论 2 292
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 29,847评论 0 182
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 33,441评论 0 228
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 29,939评论 2 232
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,333评论 1 242
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 27,783评论 2 236
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,275评论 3 220
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 25,830评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,444评论 0 180
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 34,553评论 2 249
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 34,618评论 2 249

推荐阅读更多精彩内容