android異步加載
來源:程序員人生 發布時間:2016-06-24 17:44:11 閱讀次數:2525次
轉載請說明出處,歡迎轉載。http://write.blog.csdn.net/postedit/51533261
本篇博客總結了慕課網關于異步加載圖片的知識要點,和大家1起分享,有感覺聽得不聯貫的可以來看看。
看完本篇博客,你將學習到下面的知識:
1.怎樣將1個url(也能夠說是1個InputStream)轉換為1個json字符串信息。
2.怎樣應用插件寫1個我認為完善的model類來為解析json做準備。
3.AsyncTask的基本用法。
4.Gosn的基本用法。
5.Adapter的經常使用優化寫法。
6.通過LruCache緩存已加載的圖片。
7.listview高效加載復雜item布局。
8.編寫json實體類的AS小插件。
好了,直接上代碼,代碼里面有詳細的解釋。
package com.robin.loadimageinlistview;
import android.os.AsyncTask;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ListView;
import com.google.gson.Gson;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private ListView listView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
listView = (ListView) findViewById(R.id.lv_main);
String URL1 = "http://www.imooc.com/api/teacher?type=4&num=30";
new MyAsyncTask().execute(URL1);
}
class MyAsyncTask extends AsyncTask<String, Void, List<NewsBean.BeanData>> {//<strong><span style="color:#ff0000;">(知識點3)</span></strong>
@Override
protected List<NewsBean.BeanData> doInBackground(String... params) {
return getJsonData(params[0]);
}
@Override
protected void onPostExecute(List<NewsBean.BeanData> beanDatas) {
super.onPostExecute(beanDatas);
NewsAdapter adapter = new NewsAdapter(MainActivity.this, beanDatas, listView);
listView.setAdapter(adapter);
}
}
/**
* 通過URL獲得json字符串<strong><span style="color:#ff0000;">(知識點2)</span></strong>
*
* @param url
* @return List<NewsBean.BeanData>
*/
private List<NewsBean.BeanData> getJsonData(String url) {
String jsonString = null;
try {
jsonString = readStream(new URL(url).openStream());
} catch (IOException e) {
e.printStackTrace();
}
Gson gson = new Gson();
if(jsonString==null||"".equals(jsonString))return null;//如果jsonString返回有問題,就不解析了。
NewsBean newsBean = gson.fromJson(jsonString, NewsBean.class);//<span style="color:#ff0000;"><strong>(知識點4)</strong></span>需要將Gosn的包導入進project中。怎樣導,就不詳細說了,去Google
return newsBean.getData();
}
/**
* 怎樣將1個url(也能夠說是1個InputStream)轉換為1個json字符串信息。<strong><span style="color:#ff0000;">(知識點1)</span></strong>
*
* @param is
* @return String
*/
private String readStream(InputStream is) {
String result = "";
InputStreamReader isr;
String line;
try {
isr = new InputStreamReader(is, "utf⑻");//字節流轉化為字符流
BufferedReader br = new BufferedReader(isr);
while ((line = br.readLine()) != null) {
result += line;
}
} catch (IOException e) {
e.printStackTrace();
}
return result;
}
}
接下來開始放Adapter
(知識點5)
package com.robin.loadimageinlistview;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import java.util.List;
public class NewsAdapter extends BaseAdapter implements AbsListView.OnScrollListener{
private List<NewsBean.BeanData> newsBeans;
private LayoutInflater mInflater;
private ImageLoader imageLoader;
private int mStart,mEnd;
public static String[] URLS;//寄存要加載的圖片的url
private boolean isFirst = false;//控制第1次進入listview的時候加載數據
public NewsAdapter(Context context, List<NewsBean.BeanData> newsBeans, ListView listView) {//初始化數據
this.newsBeans = newsBeans;
this.mInflater = LayoutInflater.from(context);
imageLoader = new ImageLoader(listView);// 確保只有1個LruCache
URLS = new String[newsBeans.size()];
for (int i=0;i<newsBeans.size();i++){//獲得newsBeans中的圖片的url
URLS[i] = newsBeans.get(i).getPicSmall();
}
isFirst = true;
listView.setOnScrollListener(this);
}
@Override
public int getCount() {
return newsBeans.size();
}
@Override
public Object getItem(int position) {
return newsBeans.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder;//利用viewholder進行優化,這1點也是寫類似listview的adapter的getView方法的1個模板。
if(convertView==null){
viewHolder = new ViewHolder();
convertView = mInflater.inflate(R.layout.item_layout,null);
viewHolder.ivIcon = (ImageView) convertView.findViewById(R.id.iv_icon);
viewHolder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);
viewHolder.tvContent = (TextView) convertView.findViewById(R.id.tv_content);
convertView.setTag(viewHolder);
}else{//如果convertView不為空就不用再次去加載布局了,由于加載布局耗時很長,造成listview的卡頓
viewHolder = (ViewHolder) convertView.getTag();
}
viewHolder.ivIcon.setImageResource(R.mipmap.ic_launcher);
String url = newsBeans.get(position).getPicSmall();
viewHolder.ivIcon.setTag(url);//將url作為tag
imageLoader.showImageByAsyncTask(viewHolder.ivIcon,url);
viewHolder.tvTitle.setText(newsBeans.get(position).getName());
viewHolder.tvContent.setText(newsBeans.get(position).getDescription());
return convertView;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {//滑動狀態改變時調用<span style="color:#ff0000;"><strong>(知識點7)</strong></span>
if(scrollState==SCROLL_STATE_IDLE){//停止轉動,加載可見項
imageLoader.loadImage(mStart,mEnd);
}else{//停止加載
imageLoader.cancelAllTask();
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {//全部滑動的時候都會調用
mStart = firstVisibleItem;//第1個可見元素
mEnd =firstVisibleItem+visibleItemCount;//最后1個可見元素=第1個可見元素+可見元素的數量
if(isFirst && visibleItemCount > 0){//第1次加載的時候調用,顯示圖片
imageLoader.loadImage(mStart,mEnd);
isFirst=false;
}
}
class ViewHolder{
public TextView tvTitle;
public TextView tvContent;
public ImageView ivIcon;
}
}
對
知識點7的1點解釋,當item布局非常復雜的時候,這是用戶區頻繁轉動listview,listview會頻繁調用getView方法去獲得item,致使卡頓,但是,平常的使用進程中,我們發現1般用戶轉動的時候不太注意內容,停止轉動的時候才回去看內容,因此我們斟酌如果將顯示內容的權利從getView中移交給轉動事件處理的話,這個問題就可以得到解決。
接下來上最重要的控制圖片緩存和加載的類
package com.robin.loadimageinlistview;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.util.LruCache;
import android.widget.ImageView;
import android.widget.ListView;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashSet;
import java.util.Set;
public class ImageLoader {
private LruCache<String,Bitmap> cache;//用于緩存圖片
private ListView listView;
private Set<NewsAsyncTask> mTask;//管理AsyncTask
public ImageLoader(ListView listView) {//初始化1些數據
this.listView = listView;
this.mTask = new HashSet<>();
int maxMemry = (int) Runtime.getRuntime().maxMemory();//獲得當前利用可用的最大內存
int cacheSize = maxMemry/4;//以最大的4分之1作為可用的緩存大小
this.cache = new LruCache<String,Bitmap>(cacheSize){//初始化LruCache
@Override
protected int sizeOf(String key, Bitmap value) {
return value.getByteCount();//每次存入緩存的大小,即bitmap的大小
}
};
}
/**
* 將內容保存到LruCache
* @param url
* @param bitmap
*/
public void addBitmapToCache(String url,Bitmap bitmap){
if(getBitmapFromCache(url)==null){//如果沒有保存的話就保存。
cache.put(url,bitmap);
}
}
/**
* 從LruCache中獲得bitmap
* @param url
* @return Bitmap
*/
public Bitmap getBitmapFromCache(String url){
return this.cache.get(url);
}
/**
* 將圖片url轉化為bitmap
* @param urlString
* @return Bitmap
*/
public Bitmap getBitmapFromUrl(String urlString){
Bitmap bitmap;
InputStream is=null;
try {
URL url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
is = new BufferedInputStream(connection.getInputStream());
bitmap = BitmapFactory.decodeStream(is);
connection.disconnect();
return bitmap;
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
if(is!=null){
is.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
public void showImageByAsyncTask(ImageView imageView,String url){//改進以后,獲得圖片的控制權由原來getview改成了轉動狀態。
Bitmap bitmap = getBitmapFromCache(url);//從緩存中獲得圖片
if(bitmap==null){//如果沒有就設置默許的圖片
imageView.setImageResource(R.mipmap.ic_launcher);
}else{//如果有就設置當前的圖片
imageView.setImageBitmap(bitmap);
}
}
private class NewsAsyncTask extends AsyncTask<String,Void,Bitmap>{
private String url;
public NewsAsyncTask(String url) {
this.url = url;
}
@Override
protected Bitmap doInBackground(String... params) {
String url = params[0];
Bitmap bitmap = getBitmapFromUrl(url);//獲得網絡圖片
if(bitmap!=null){
addBitmapToCache(url,bitmap); //將不在緩存的圖片加載的緩存中去
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
ImageView imageView =(ImageView) listView.findViewWithTag(url);
if(imageView!=null&&bitmap!=null){//判斷這個url所對應的imageview是不是對應,對應的話才設置圖片,
imageView.setImageBitmap(bitmap);
}
}
}
/**
* 加載從start到end的所有圖片
* @param start
* @param end
*/
public void loadImage(int start,int end){
for (int i= start;i<end;i++){//拿到數組中的圖片對應的url
String url = NewsAdapter.URLS[i];
Bitmap bitmap = getBitmapFromCache(url);
if(bitmap==null){//沒有就要去下載
NewsAsyncTask newsAsyncTask = new NewsAsyncTask(url);
newsAsyncTask.execute(url);
mTask.add(newsAsyncTask);
}else{
ImageView imageView =(ImageView) listView.findViewWithTag(url);//通過findViewWithTag找到imageview,這個tag就是imageview的url
imageView.setImageBitmap(bitmap);
}
}
}
public void cancelAllTask() {
if(mTask!=null){
for (NewsAsyncTask task:mTask) {
task.cancel(false);
}
}
}
}
最后送上1個小插件
(知識點8),只恨自己執導的太晚,要是有個這個奇異,實體類就不在這么難寫了。再次分享給大家,特別是企業開發的時候,常常能用到,上 git地址,包括用法,安裝很詳細的。
https://github.com/zzz40500/GsonFormat
好了,大概就這些了,上傳1張效果圖

最后感謝大家,喜歡請點贊,有疑問,可以回復交換,有毛病,請指出。Thx。
轉載請說明出處,歡迎轉載。http://write.blog.csdn.net/postedit/51533261
阿斯頓
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈