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載入 滑動時停止載入,停止時載入可見項
- 非同步載入網路圖片(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);
}
- 改造載入邏輯,進一步優化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);
}
}
}