緩存—>SD卡—>網絡
ImageLoader
package com.example.jack.myapplication.utils;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Environment;
import android.util.Log;
import android.util.LruCache;
import android.widget.ImageView;
import com.example.jack.myapplication.R;
import com.example.jack.myapplication.consts.MyHttpURL;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
/**
* 用於下載、顯示圖片
* Created by ding on 2015/10/26.
*/
public class ImageLoader {
//緩存
private LruCache<String, Bitmap> mCaches;
private String bitmapFileName ;
//構造方法
public ImageLoader() {
//獲取最大可用內存
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory / 4;
mCaches = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
//在每次存入緩存時調用,存入圖片大小
return value.getByteCount();
}
};
}
//將圖片寫入緩存
public void addBitmapToCache(String bitmapFileName, Bitmap bitmap) {
//先判斷bitmap是否爲空
if (getBitmapFromCache(bitmapFileName) == null) {
mCaches.put(bitmapFileName, bitmap);
}
}
//根據url獲得緩存的圖片
public Bitmap getBitmapFromCache(String bitmapFileName) {
if(bitmapFileName!=null){
return mCaches.get(bitmapFileName);
}else {
return null ;
}
}
/**
* 通過url獲得圖片
*
* @param urlString
* @return
*/
public Bitmap getBitmapFromURL(String urlString) {
if(urlString.equals(MyHttpURL.IP+null)||urlString.equals(MyHttpURL.IP)){
return null ;
}
Bitmap bitmap;
InputStream is = null;
URL url;
try {
url = new URL(urlString);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
Log.i("getBitmapFromURL參數url爲:",urlString);
InputStream ins = connection.getInputStream();
//緩衝流
is = new BufferedInputStream(ins);
//將is轉化爲bitmap
bitmap = BitmapFactory.decodeStream(is);
//添加網絡中下載的bitmap到緩存和本地sd卡
addBitmapToCache(urlString,bitmap);
addBitmapToFile(urlString,bitmap);
//關閉連接
connection.disconnect();
return bitmap;
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return null;
}
File dir = null;
/**
* 將圖片文件寫入文件
* @param url
* @param bitmap
*/
public void addBitmapToFile(String url,Bitmap bitmap){
//Environment.getExternalStorageState()方法用於獲取SDCard的狀態,如果手機裝有SDCard,
//並且可以進行讀寫,那麼方法返回的狀態等於Environment.MEDIA_MOUNTED
if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)){
FileOutputStream fos = null ;
//創建根目錄文件對象
if(dir == null){
dir = new File("/mnt/sdcard/test/");
}
//如果根目錄文件對象不存在
if (!dir.exists()) {
dir.mkdirs();
}
File bitmapFile = null ;
//創建圖片文件對象
if(bitmapFile == null){
bitmapFile = new File("/mnt/sdcard/test/" +
url.substring(url.lastIndexOf("/") + 1));
}
//如果圖片文件對象不存在,則創建新的文件
if (!bitmapFile.exists()) {
try {
bitmapFile.createNewFile();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try {
if(fos == null ){
//得到文件輸出流
fos = new FileOutputStream(bitmapFile);
}
//將圖片文件寫進文件中
bitmap.compress(Bitmap.CompressFormat.PNG , 100 , fos);
fos.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
/**
* 通過AsyncTask顯示圖片:從緩存中找--->從本地文件中找--->從網絡中找
* @param imageView
* @param imageUrl
*/
public void showImageByAsyncTask(ImageView imageView, String imageUrl) {
int i = 0 ;
//根據url構建圖片文件名
bitmapFileName = imageUrl.substring(imageUrl.lastIndexOf("/") + 1);
//從緩存中取名爲url的圖片
Bitmap bitmap = getBitmapFromCache(bitmapFileName);
Log.i("提示:","從緩存中得到的圖片"+bitmap);
//如果緩存中沒有,則先從本地文件中找
if (bitmap == null) {
Log.i("提示:","SD卡中圖片的文件名"+bitmap);
//創建根目錄文件對象
if(dir == null){
dir = new File("/mnt/sdcard/test/");
}
//得到文件列表
File[] cacheFiles = dir.listFiles();
Log.i("提示:","文件列表爲:"+cacheFiles);
Log.i("提示:","文件列表的大小:"+cacheFiles.length);
if (cacheFiles != null) {
//逐一查找
for (; i < cacheFiles.length; i++) {
//如果文件列表中存在與圖片文件名相同的文件,則跳出for循環
if (bitmapFileName.equals(cacheFiles[i].getName())) {
break;//跳出for循環
}
}
//如果i < cacheFiles.length,說明存在圖片文件
if (i < cacheFiles.length) {
imageView.setImageBitmap(BitmapFactory.decodeFile("/mnt/sdcard/test/" + bitmapFileName));
Log.i("提示:", "顯示的圖片從SD卡中來");
//將SD卡的圖片放到緩存中
addBitmapToCache(bitmapFileName, BitmapFactory.decodeFile("/mnt/sdcard/test/" + bitmapFileName));
return;//跳出方法
}else{
//如果文件列表都沒有,則從網絡中找
LessonsIconAsyncTask task = new LessonsIconAsyncTask(imageView);
//執行task
task.execute(imageUrl);
}
}
//文件夾都不存在,則圖片也不存在
else{
//如果文件列表都沒有,則從網絡中找
LessonsIconAsyncTask task = new LessonsIconAsyncTask(imageView);
//執行task
task.execute(imageUrl);
}
} else {
//緩存中存在,則直接顯示圖片
imageView.setImageBitmap(bitmap);
Log.i("提示:","顯示的圖片從緩存中來");
}
}
/**
* 自定義的AsyncTask,傳進的類型、返回過程、返回的類型
*/
private class LessonsIconAsyncTask extends AsyncTask<String, Void, Bitmap> {
private ImageView mImageView ;
//構造方法
private LessonsIconAsyncTask(ImageView imageView) {
mImageView = imageView ;
}
@Override
protected Bitmap doInBackground(String... params) {
//圖片url
String url = params[0];
//從網絡中獲取圖片
Bitmap bitmap = getBitmapFromURL(url);
//如果從網絡中獲得的圖片不爲空
if (bitmap != null) { // 1、將圖片寫入緩存 2、將圖片寫入文件
//將圖片以url爲標誌寫入緩存
addBitmapToCache(bitmapFileName, bitmap);
//將圖片寫入文件
addBitmapToFile(bitmapFileName, bitmap);
}
return bitmap;
}
//上面doInBackground返回的bitmap在這裏處理
@Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
//如果該imageView不爲空且bitmap不爲空
if (mImageView != null && bitmap != null) {
//imageView顯示圖片
mImageView.setImageBitmap(bitmap);
Log.i("提示:", "顯示的圖片從網絡中來");
}else {
mImageView.setImageResource(R.mipmap.no);
Log.i("提示:", "顯示的圖片爲默認圖片");
}
}
}
}
LessonListAdapter
package com.example.jack.myapplication.adapter;
import android.content.Context;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import com.example.jack.myapplication.R;
import com.example.jack.myapplication.entity.Lesson;
import com.example.jack.myapplication.utils.ImageLoader;
import java.util.List;
/**
* listView的適配器
* Created by ding on 2015/10/13.
*/
public class LessonListAdapter extends BaseAdapter {
//保存所有需要顯示的圖片的url地址
public String[] imageUrls;
//數據源:課程信息集合
List<Lesson> lessons;
//運行上下文
private Context context;
//視圖容器
private LayoutInflater inflater;
//圖片下載的工具類
private ImageLoader mImageLoader;
//構造方法
public LessonListAdapter(Context context, List<Lesson> lessons, ListView listView) {
//並設置上下文
this.context = context;
//創建視圖容器
inflater = LayoutInflater.from(context);
//數據源
this.lessons = lessons;
imageUrls = new String[lessons.size()];
for (int i = 0; i < lessons.size(); i++) {
//將圖片url保存到該數組裏面
imageUrls[i] = lessons.get(i).getLIcon();
}
//初始化ImageLoader,加載顯示圖片的工具類,將listview傳進去
mImageLoader = new ImageLoader();
}
// 在此適配器中所代表的數據集中的條目數
public int getCount() {
return lessons.size();
}
//獲取數據集中與指定索引對應的 數據項
public Object getItem(int position) {
return lessons.get(position);
}
//取在列表中與指定索引對應的行id
public long getItemId(int position) {
return position;
}
/*
ListView Item設置 :獲取一個在數據集中指定索引的視圖來顯示數據
*/
@Override
public View getView(int position, View convertView, ViewGroup parent) {
//控件集
ViewHolder holder = null;
//如果緩存convertView爲空,則需要創建View
if (convertView == null) {
//實例化控件集
holder = new ViewHolder();
//獲取list_item佈局文件的視圖 : 根據自定義的Item佈局加載佈局
convertView = inflater.inflate(R.layout.lesson_item, null);
//獲取控件對象
holder.ivLessonIcon = (ImageView) convertView.findViewById(R.id.ivLessonIcon);
holder.tvLessonName = (TextView) convertView.findViewById(R.id.tvLessonName);
holder.tvLessonSectionNumber = (TextView) convertView.findViewById(R.id.tvLessonSectionNumber);
//將設置好的佈局保存到緩存(convertView )中,並將其設置在Tag裏,以便後面方便取出Tag
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
Lesson lesson = (Lesson) getItem(position);
//圖片url
String url = lesson.getLIcon();
Log.i("提示:", "圖片url爲:" + url);
//調用mImageLoader中的showImageByAsyncTask方法加載並顯示圖片
mImageLoader.showImageByAsyncTask(holder.ivLessonIcon, url);
holder.tvLessonName.setText(lesson.getLName());
holder.tvLessonSectionNumber.setText(lesson.getLCount() + " 人學習");
return convertView;
}
//自定義控件集合 :優化性能,按需填充並重新使用view來減少對象的創建。
class ViewHolder {
private ImageView ivLessonIcon;//課程圖標
private TextView tvLessonName;//課程標題
private TextView tvLessonSectionNumber;//課程學習人數
}
}