Android - AsyncTask (SDK 24)

利用AsyncTask給ListView異步加載圖片 實(shí)現(xiàn)圖文混排

#  AsyncTask
 // 無參 無進(jìn)度顯示 有返回值
JSONObjectpublic class NewsTask extends AsyncTask<Void,Void,JSONObject> {   
   private Activity activity;  
   private String url;   
   private OnTaskListener listener;   

 //構(gòu)造方法  將 act 以及 url 傳進(jìn)來  listen實(shí)例化    
public NewsTask (Activity activity, String url,OnTaskListener onTaskListener) { 
  this.activity = activity;       
  this.url = url;        
  this.listener = onTaskListener;    
}   

 // 將 url 對應(yīng)的json數(shù)據(jù) 轉(zhuǎn)為  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字符串轉(zhuǎn)為 json對象        
} catch (IOException e) {           
 e.printStackTrace();        
}catch (JSONException e) {            
  e.printStackTrace();        
}        return  jsonObject;    
}  
// 轉(zhuǎn)成 json 字符串    
private String readStream (InputStream is){        
  InputStreamReader isr;        
  String result ="";        
try {            
  String line = "";            
  // 通過定義字符集格式 將字節(jié)流 轉(zhuǎn)為 字符流
  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;    
}    

// 子線程 任務(wù)    
@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("數(shù)據(jù)為空");        
}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;      
  //  操作數(shù)據(jù)      
  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 與 數(shù)據(jù)綁定         
   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;  //創(chuàng)建靜態(tài)數(shù)組
    private boolean firstFlag;

    public NewsAdapter(List<NewsBean> beanList, Context context) {
        this.beanList = beanList;
        this.context = context;
        inflater = LayoutInflater.from(context);
        imgLoader = new ImageThreadLoader();

        // 將所有 newsImgUrl 單獨(dú)出來成為一個靜態(tài)數(shù)組
      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 方式  依次執(zhí)行任務(wù)
//        new ImageThreadLoader().setImageByAsyncTask(holderView.mImgView,bean.newsImgUrl);

        // 使用LruCache 以內(nèi)存換效率
       // imgLoader.setImageByAsyncTask(holderView.mImgView,bean.newsImgUrl);

        holderView.mTitle.setText(bean.newsTitle);
        holderView.mContent.setText(bean.newsContent);
    }

// AbsListView.OnScrollListener 滑動監(jiān)聽
@Overridepublic
 void onScrollStateChanged(AbsListView view, int scrollState) {
    // 狀態(tài)改變
    if (scrollState == SCROLL_STATE_IDLE){
        //  滾動停止  加載數(shù)據(jù)
        imgLoader.loadImages(startIdx,endIdx);
    }else {
        // 停止后臺線程 保證滾動的流暢
        imgLoader.cancleAllTasks();
    }
}
//  onScroll 一開始就會執(zhí)行
@Overridepublic
 void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    startIdx = firstVisibleItem; // 第一個可見項(xiàng)
    endIdx = firstVisibleItem + visibleItemCount;  // 最后一個可見項(xiàng)
    if (firstFlag && totalItemCount > 0){
        // 第一次 第一屏 加載 (此時 未主動滑動 且 totalItemCount不為0而且已經(jīng)計(jì)算出來)
        imgLoader.loadImages(startIdx,endIdx);
        firstFlag = false;
    }
}
    // ViewHolder 內(nèi)部類
    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 一一對應(yīng)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);   //發(fā)送消息
            }
        }.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;
    }

// 構(gòu)造方法  外界 實(shí)例化ImageThreadLoader的成員變量 保證只有一個 LruCache對象
public ImageThreadLoader() {
mListView = listView;
// 初始化 集合
mVisiableTasks = new HashSet<>();
    // 獲得當(dāng)前 最大可以內(nèi)存
    int maxSize = (int) Runtime.getRuntime().maxMemory();
    //  分多少內(nèi)存給緩存
    int cacheSize = maxSize / 4;
    // 實(shí)例化
    mCache = new LruCache<String, Bitmap>(cacheSize){
        // 必須實(shí)現(xiàn)的方法 返回每次存入時 key 對應(yīng)的value的大小
        @Override
        protected int sizeOf(String key, Bitmap value) {
            return value.getByteCount();
        }
    };
}
private void addToCache(String key,Bitmap value){
    if (getFromCache(key) == null){
  // 內(nèi)存中不存在
        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;
    // 先從緩存中取數(shù)據(jù)
    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];
        // 先從緩存中取數(shù)據(jù)
        Bitmap bitmap = getFromCache(url);
        if (bitmap == null){
            // 沒有緩存 下載
            ImageAsycTask task = new ImageAsycTask(url);
            task.execute(url);
            mVisiableTasks.add(task);    // 加到Set集合中
        }else {
            // listView 根據(jù) tag 找到url對應(yīng)的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獨(dú)立出來以及 定義接口和將返回值 定義成 JSONObject  都是為了封裝
    public void onSucceed(JSONObject jsonObject);
    public void onFailed(String msg);
}

鏈接

AsyncTask源碼分析

知乎

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市益老,隨后出現(xiàn)的幾起案子彪蓬,更是在濱河造成了極大的恐慌,老刑警劉巖捺萌,帶你破解...
    沈念sama閱讀 221,406評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件档冬,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)酷誓,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,395評論 3 398
  • 文/潘曉璐 我一進(jìn)店門披坏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人盐数,你說我怎么就攤上這事刮萌。” “怎么了娘扩?”我有些...
    開封第一講書人閱讀 167,815評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長壮锻。 經(jīng)常有香客問我琐旁,道長,這世上最難降的妖魔是什么猜绣? 我笑而不...
    開封第一講書人閱讀 59,537評論 1 296
  • 正文 為了忘掉前任灰殴,我火速辦了婚禮,結(jié)果婚禮上掰邢,老公的妹妹穿的比我還像新娘牺陶。我一直安慰自己,他們只是感情好辣之,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,536評論 6 397
  • 文/花漫 我一把揭開白布掰伸。 她就那樣靜靜地躺著,像睡著了一般怀估。 火紅的嫁衣襯著肌膚如雪狮鸭。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,184評論 1 308
  • 那天多搀,我揣著相機(jī)與錄音歧蕉,去河邊找鬼。 笑死康铭,一個胖子當(dāng)著我的面吹牛惯退,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播从藤,決...
    沈念sama閱讀 40,776評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼催跪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了呛哟?” 一聲冷哼從身側(cè)響起叠荠,我...
    開封第一講書人閱讀 39,668評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎扫责,沒想到半個月后榛鼎,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,212評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,299評論 3 340
  • 正文 我和宋清朗相戀三年者娱,在試婚紗的時候發(fā)現(xiàn)自己被綠了抡笼。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,438評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡黄鳍,死狀恐怖推姻,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情框沟,我是刑警寧澤藏古,帶...
    沈念sama閱讀 36,128評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站忍燥,受9級特大地震影響拧晕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜梅垄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,807評論 3 333
  • 文/蒙蒙 一厂捞、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧队丝,春花似錦靡馁、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,279評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至吞加,卻和暖如春裙犹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背衔憨。 一陣腳步聲響...
    開封第一講書人閱讀 33,395評論 1 272
  • 我被黑心中介騙來泰國打工叶圃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人践图。 一個月前我還...
    沈念sama閱讀 48,827評論 3 376
  • 正文 我出身青樓掺冠,卻偏偏與公主長得像,于是被迫代替她去往敵國和親码党。 傳聞我的和親對象是個殘疾皇子德崭,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,446評論 2 359

推薦閱讀更多精彩內(nèi)容