1. 程式人生 > >Android非同步載入(慕課網學習筆記)

Android非同步載入(慕課網學習筆記)

最近看了慕課網的教學視訊,這裡記錄一下學習筆記.
學習視訊地址:http://www.imooc.com/learn/406
視訊完成的小例子很簡單,就是展示一個帶圖片的列表.如下圖所示:
這裡寫圖片描述
首先把MainActivity的佈局,ListView的Item佈局 listView要用的Adapter寫好,這個程式碼很簡單就不貼了.
然後從網上獲取資料並解析.請求資料的網址為:http://www.imooc.com/api/teacher?type=4&num=30 獲取到的資料為Json格式.對應的網路請求和資料解析在NewsUtil.java中完成

    public class NewsUtil
{
/** * 讀取流中的字串 ada * * @param is * @return */ public static String readStream(InputStream is) { StringBuilder sb = new StringBuilder(); try { InputStreamReader isr = new InputStreamReader(is, "utf-8"); BufferedReader br = new BufferedReader(isr); String line = ""
; while ((line = br.readLine()) != null) { sb.append(line); } } catch (Exception e) { e.printStackTrace(); } return sb.toString(); } /** * 解析json字串 ada * * @param url * @return */ public static
List<NewsInfo> getJsonData(String url) { List<NewsInfo> datas = new ArrayList<NewsInfo>(); try { InputStream inputStream = new URL(url).openStream(); String jsonString = readStream(inputStream); Log.e("ada", jsonString); JSONObject jsonObject = new JSONObject(jsonString); JSONArray jsonArray = jsonObject.getJSONArray("data"); for (int i = 0; i < jsonArray.length(); i++) { JSONObject object = jsonArray.getJSONObject(i); NewsInfo newsInfo = new NewsInfo(); newsInfo.title = object.getString("name"); newsInfo.content = object.getString("description"); newsInfo.url = object.getString("picSmall"); datas.add(newsInfo); } } catch (Exception e) { e.printStackTrace(); } Log.e("ada", "datas size:"+datas.size()); return datas; } }

readStream()方法根據請求的連結拿到對應的json字串
getJsonData()解析json字串並封裝好供listView使用
解析Json字串是要建立對應的javaBean檔案NewsInfo.java
NewsInfo.java

/**
 * 新聞列表結構體
 * 
 * @author ada 2016年10月8日
 * 
 */
public class NewsInfo {
    public String title;/**標題**/
    public String content;/**內容**/
    public String url;/**圖片的下載地址**/
}

然後在MainActivity中進行非同步載入,獲取資料成功後,重新整理介面,展示列表.(此時還未對圖片進行載入,使用的預設圖)非同步載入使用的AsyncTask

    private class MyAsyncTask extends AsyncTask<String, Void, List<NewsInfo>> {

        @Override
        protected List<NewsInfo> doInBackground(String... params) {
            // 子執行緒中獲取解析資料
            return NewsUtil.getJsonData(params[0]);
        }

        @Override
        protected void onPostExecute(List<NewsInfo> result) {
            super.onPostExecute(result);
            // 主執行緒中重新整理頁面
            lv.setAdapter(new NewsAdapter(MainActivity.this, result,lv));
        }
    }

接下來對來寫列表中的圖片載入方法,首先在NewsUtil中增加獲取圖片的方法getBitmapFromURL

        public static Bitmap getBitmapFromURL(String path) {
        InputStream is = null;
        Bitmap bitmap;
        try {
            is = new URL(path).openStream();
            bitmap = BitmapFactory.decodeStream(is);
            return bitmap;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (is != null)
                    is.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

然後新建類ImageLoder類,在裡面處理圖片載入邏輯,並對圖片載入進行優化管理
ImageLoder中主要做了這幾件事:
1. 非同步載入網路圖片(thread或asyncTask皆可)
2. 利用LruCache提高使用者體驗,優化ListView圖片載入
3. 改造載入邏輯,進一步優化ListView載入 滑動時停止載入,停止時載入可見項

  1. 非同步載入網路圖片(thread或asyncTask皆可)對應的程式碼
    private class ImageAsyncTask extends AsyncTask<String, Void, Bitmap> {
        private String url;


        public ImageAsyncTask(String url) {
            this.url = url;
        }

        @Override
        protected Bitmap doInBackground(String... params) {
            String backGroundUrl = params[0];
            Bitmap bitmap = NewsUtil.getBitmapFromURL(backGroundUrl);
            //新增圖片到快取
            if (bitmap != null) {
                addBitmapToLru(url, bitmap);

            }
            return bitmap;
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            super.onPostExecute(result);
            mImageView = (ImageView) listView.findViewWithTag(url);
            if (mImageView != null && result != null) {
                mImageView.setImageBitmap(result);
            }
            mTasks.remove(this);
        }
    }

        2. 利用LruCache提高使用者體驗,優化ListView圖片載入
            // 初始化LeruCache
        int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 4);
        lruCache = new LruCache<String, Bitmap>(maxMemory) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                // 每次存入快取的時候呼叫,返回存入物件的大小。
                return value.getByteCount();
            }
        };
            /**
     * 新增圖片到快取
     * ada
     * @param key
     * @param value
     */
    public void addBitmapToLru(String key, Bitmap value) {
        if (getBitmapFromLru(key) == null) {
            lruCache.put(key, value);

        }
    }

    /**
     * 從快取中獲取圖片
     * ada
     * @param key
     * @return
     */
    public Bitmap getBitmapFromLru(String key) {
        return lruCache.get(key);
    }
  1. 改造載入邏輯,進一步優化ListView載入 滑動時停止載入,停止時載入可見項
    Adapter實現方法OnScrollListener
     @Override
    public void onScrollStateChanged(AbsListView view, int scrollState) {
        if (scrollState == SCROLL_STATE_IDLE) {
            //載入可見項
            imageLoader.loadImages(mStart,mEnd);
        }else {
            //停止載入所有
            imageLoader.cacelAllTask();
        }

    }

    @Override
    public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
        mStart = firstVisibleItem;
        mEnd = firstVisibleItem + visibleItemCount;
        //處理預載入
        if (mFrist && visibleItemCount > 0) {
            imageLoader.loadImages(mStart, mEnd);
            mFrist = false;
        }

ImageLode中增加對應的loadImages()和cacelAllTask()

    /**
     * 根據起始位置載入指定圖片
     * ada
     * @param mStart
     * @param mEnd
     */
    public void loadImages(int mStart, int mEnd) {
        for (int i = mStart; i < mEnd; i++) {
            String url = NewsAdapter.URLS[i];
            Bitmap bitmap = getBitmapFromLru(url);
            if (bitmap == null) {
                ImageAsyncTask asyncTask = new ImageAsyncTask(url);
                asyncTask.execute(url);
                mTasks.add(asyncTask);

            } else {
                 mImageView = (ImageView) listView.findViewWithTag(url);
                 mImageView.setImageBitmap(bitmap);
            }
        }
    }

    public void cacelAllTask() {
        if (mTasks != null) {
            for (ImageAsyncTask task : mTasks) {
                task.cancel(false);
            }

        }

    }