AsyncTask異步加載

item.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

     <ImageView 
        android:layout_height="60dp"
        android:layout_width="60dp"
        android:id="@+id/image"
        android:background="@drawable/ic_launcher"/>

    <TextView 
        android:layout_height="30dp"
        android:layout_width="match_parent"
        android:id="@+id/title"
        android:layout_toRightOf="@+id/image"
        android:gravity="center"
        android:text="標題"
        android:maxLines="1"
        android:textSize="25sp"
        />
   <TextView 
        android:layout_height="30dp"
        android:layout_width="match_parent"
        android:id="@+id/content"
        android:layout_below="@+id/title"
        android:layout_toRightOf="@+id/image"
        android:gravity="center"
        android:text="內容"
        android:maxLines="3"
        />


</RelativeLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <ListView 
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/lv">
    </ListView>

</LinearLayout>

NewsBean.java
用於封裝每一個列表項所對應的數據源信息

package com.example.newsasynctask;

public class NewsBean {
    public String newsIconURL;//圖片網址
    public String newsTitle;
    public String newsContent;

}

MainActivity.java
1.新建一個MyAsyncTAsk對象並給其傳遞一個uri
2.實現對url(網頁)的異步訪問

package com.example.newsasynctask;

import java.io.BufferedReader;
import java.net.URL;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.ListView;

public class MainActivity extends Activity {

    //聲明JsonString
    final private String url="http://www.imooc.com/api/teacher?type=4&num=30";
    private ListView lv;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        lv=(ListView) findViewById(R.id.lv);
        /*
         * 1.新建一個MyAsyncTAsk對象並給其傳遞一個uri
         */
        new MyAsyncTask().execute(url);
    }

    /*
     * 將 url對應的JSON格式數據轉化爲所封裝的的NewsBean對象
     */
    private List<NewsBean>  getJsonData(String url){
        List<NewsBean> newsBeanList=new ArrayList<>();//用於封裝所有json格式的數據
        try {
            String JsonString=readStream(new URL(url).openStream());
            JSONObject jsonObject;
            NewsBean newsBean;//用於封裝屬性
            try {
                //將json格式的String轉化爲JSONObject
                jsonObject = new JSONObject(JsonString);
                //取出JSONArray:data
                JSONArray jsonArray=jsonObject.getJSONArray("data");
                //通過遍歷JSONArray取出每一個JSONObject並取出對應的值
                for (int i = 0; i < jsonArray.length(); i++) {
                    jsonObject=jsonArray.getJSONObject(i);
                    newsBean=new NewsBean();
                    newsBean.newsIconURL=jsonObject.getString("picSmall");
                    newsBean.newsTitle=jsonObject.getString("name");
                    newsBean.newsContent=jsonObject.getString("description");
                    newsBeanList.add(newsBean);
                }
            } catch (JSONException e) {
                e.printStackTrace();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return newsBeanList;
    }
    /*
     * 通過InputStream解析網頁返回的數據
     */
    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 (Exception e) {
            e.printStackTrace();
        }
        return result;
    }
    /*
     * 2.實現對url(網頁)的異步訪問
     */
    class MyAsyncTask extends AsyncTask<String,Void,List<NewsBean>>{
        /*
         * 3.將 url對應的JSONS格式數據轉化爲所封裝的的NewsBean對象
         */
        @Override
        protected List<NewsBean> doInBackground(String... params) {
            return getJsonData(params[0]);
        }
        /*
         * 4.將生成的NewsBean傳遞給NewsAdapter,通過NewsAdapter構造一個iew類型的數據源,並將該數據源傳遞給ListView 
         */
        @Override
        protected void onPostExecute(List<NewsBean> newsBeans) {
//          super.onPostExecute(newsBeans);
            NewsAdapter adapter=new NewsAdapter(MainActivity.this, newsBeans);
            lv.setAdapter(adapter);
        }

    }
}

NewsAdapter.java

package com.example.newsasynctask;

import java.util.List;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.webkit.WebView.FindListener;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.TextView;

1.初始化數據源:URLS,inflater

public class NewsAdapter extends BaseAdapter{
   private List<NewsBean>list;
   private LayoutInflater inflater;
   private ImageLoader mImageLoader;
   private int mStart,mEnd;
   static String[] URLS;

public NewsAdapter(Context context,List<NewsBean> list) {
    this.list = list;
    inflater=LayoutInflater.from(context);
    //初始化一個ImageLoader而不是在getView方法中每次新建一個ImageLoader,來保證只有一個LruCache
    mImageLoader=new ImageLoader();
    //存儲所有列表的圖片網址
    URLS=new String[list.size()];
    for (int i = 0; i < list.size(); i++) {
        URLS[i]=list.get(i).newsIconURL;
    }
}

2.將佈局轉化爲view(利用了ListView的緩存機制,用ViewHolder將需要緩存的那些view封裝好,用convertView的setTag將這些緩存起來供下次調用)

關於 ListView中convertView和ViewHolder的工作原理,見:
http://blog.csdn.net/bill_ming/article/details/8817172

@Override
public int getCount() {
    return list.size();
}

@Override
public Object getItem(int position) {
    return list.get(position);
}

@Override
public long getItemId(int position) {
    return position;
}

@Override
public View getView(int position , View convertView, ViewGroup parent) {
    ViewHolder viewHolder=null;
    if (convertView==null) {
        viewHolder=new ViewHolder();
        convertView=inflater.inflate(R.layout.item, null);
        //對viewHolder中的元素進行初始化
        viewHolder.Icon=(ImageView) convertView.findViewById(R.id.image);
        viewHolder.title=(TextView) convertView.findViewById(R.id.title);
        viewHolder.content=(TextView) convertView.findViewById(R.id.content);
        convertView.setTag(viewHolder);
    }
    else{
        viewHolder=(ViewHolder) convertView.getTag();
    }
    String url=list.get(position).newsIconURL;
    viewHolder.Icon.setTag(url);//將ImageView與對應的 url對應的圖片進行了綁定

    //使用AsyncTask實現異步加載
    mImageLoader.showImageByAsyncTask(viewHolder.Icon, list.get(position).newsIconURL);
    viewHolder.title.setText(list.get(position).newsTitle);
    viewHolder.content.setText(list.get(position).newsContent);
    return convertView;
}
   class ViewHolder{
      public TextView title,content;
      public ImageView Icon;
   }

}

ImageLoader.java

package com.example.newsasynctask;

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;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.support.v4.util.LruCache;
import android.widget.ImageView;
import android.widget.ListView;

1.創建Cache並初始化

/*
 * 非主線程不能在線程中直接更新UI,只能用UI進行線程的傳遞
 */
public class ImageLoader {
    private ImageView mImageView;
    private String mURL;
    //創建Cache
    /*
     * 參數1:要保存對象的名字
     * 參數2:要保存對象
     */
    private LruCache<String,Bitmap> mCache;
    /*
     * 構造方法,初始化LruCache,mList,mTask
     */
    public ImageLoader(){
        //獲取最大內存
        int maxMemory=(int) Runtime.getRuntime().maxMemory();
        //設定所需要的緩存的大小
        int cacheSize=maxMemory/4;
        mCache=new LruCache<String,Bitmap>(cacheSize){
            //重寫sizeOf()方法方法,用於獲取正確的內存大小
            @Override
            protected int sizeOf(String key, Bitmap value) {
                //在每次存入緩存的時候調用
                return value.getByteCount();
            }
        };
    }

addBitmapToCache:增加到緩存,在增加之前需要先校驗一下當前緩存是否存在
getBitmapFromCache:從緩存中獲取數據

/*
 *增加到緩存,在增加之前需要先校驗一下當前緩存是否存在
 */
    public void addBitmapToCache(String url,Bitmap bitmap){
        if(getBitmapFromCache(url)==null){
            mCache.put(url, bitmap);
        }
    }
    /*
     * 從緩存中獲取數據
     */
    //LruCache底層是由LinkedHashMap來實現的,所以其本質上相當於一個map,可以調用map的許多方法,如get(),put()
    public Bitmap getBitmapFromCache(String url){
        return  mCache.get(url);
    }

showImageByAsyncTask:顯示圖片:從緩存中加載/下載圖片

/*
 * 顯示圖片:從緩存中加載/下載圖片
 */
public void showImageByAsyncTask(ImageView imageView,String url){
    //從緩存中加載圖片
    Bitmap bitmap=getBitmapFromCache(url);
    //如果緩存中沒有,則必須下載
    if(bitmap==null){
        new NewsAsyncTask(imageView,url).execute(url);
//      imageView.setImageResource(R.drawable.ic_launcher);
    }
    else{
        imageView.setImageBitmap(bitmap);
    }
}

getBitmapfromURL:將url解析成Bitmap

/*
 * 將url解析成Bitmap
 */
public Bitmap getBitmapfromURL(final String urlString) throws InterruptedException{
    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();
        Thread.sleep(1000);
        return bitmap;

    } catch (IOException e) {
        e.printStackTrace();
    }finally{
            try {
                if(is!=null)
                is.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
    }
    return null;
}

2.定義類NewsAsyncTask:從網絡獲取圖片並加入緩存

/*
 * 從網絡獲取圖片並加入緩存
 */
private class NewsAsyncTask extends AsyncTask<String,Void,Bitmap>{
    private ImageView mImageView;
    private String mURL;
    public NewsAsyncTask(ImageView imageView,String url) {
        mImageView=imageView;
        mURL=url;
    }
    @Override
    //異步任務
    protected Bitmap doInBackground(String...params) {
        try {
            String url=params[0];
            //從網絡獲取圖片
            Bitmap bitmap=getBitmapfromURL(url);
            //將不在緩存的圖片加入緩存
            if (bitmap!=null) {
                addBitmapToCache(url, bitmap);
            }
            return bitmap;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return null;
    }
/*
 * 爲ImageView設置數據源
 */
   @Override
protected void onPostExecute(Bitmap bitmap) {
    super.onPostExecute(bitmap);
    if(mImageView.getTag()==null){//初始化時並未設置Tag

         mImageView.setTag(mURL);
    }else if(mImageView.getTag().equals(mURL)){//已經設置過Tag

        mImageView.setImageBitmap(bitmap);

    }

}
}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章