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);
}
}
}
}