您的位置:首页 > 移动开发 > Android开发

Android 自定义 ImageLoader

2016-01-13 14:03 330 查看
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Hashtable;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.LinkedBlockingDeque;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.MessageQueue;
import android.support.v4.util.LruCache;
import android.test.UiThreadTest;
import android.text.TextUtils;
import android.widget.ImageView;

/**
* 网络图片加载
*
* @author
*
*/
public class ImageNetLoader {

private static final int TIMEOUT = 30 * 1000;
// protected final HashMap<String, SoftReference<Bitmap>> bitmapMap;
Context mContext;
BitmapFactory.Options opts = null;
@SuppressWarnings("rawtypes")
LruCache mMemoryCache = null;
private static ImageNetLoader imageNetLoader;

private BlockingQueue<FutureTask<Bitmap>> blockingqeque = new LinkedBlockingQueue<FutureTask<Bitmap>>();
private Thread loadThread = new Thread(){
public void run() {
while(true){
FutureTask<Bitmap> task;
try {
task = blockingqeque.take();
if(task.isCancelled() ||task.isDone() )
continue;
task.run();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}
};
};

public interface LocalFileNameBuilder {
public String getName(String url, String localDir);
}

private ImageNetLoader(Context mContext) {
this.mContext = mContext;
int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
// 使用最大可用内存值的1/8作为缓存的大小。
int cacheSize = maxMemory / 8;
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// 重写此方法来衡量每张图片的大小,默认返回图片数量。
return bitmap.getByteCount() / 1024;
}
};

}

public static ImageNetLoader instance(Context context) {
if (imageNetLoader == null) {
synchronized (ImageNetLoader.class) {
if (imageNetLoader == null) {
imageNetLoader = new ImageNetLoader(context);
imageNetLoader.loadThread.setPriority(Thread.MIN_PRIORITY);
imageNetLoader.loadThread.start();
}
}
}

return imageNetLoader;
}
@SuppressWarnings("unchecked")
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}

@SuppressWarnings("unchecked")
public Bitmap getBitmapFromMemCache(String key) {
return (Bitmap) mMemoryCache.get(key);
}

@SuppressWarnings("unchecked")
public void removeFromCache(String key) {
if (mMemoryCache.get(key) != null) {
mMemoryCache.remove(key);
}
}

/**
* 获取URL 并且保存到本地
*
* @param urlString
* @param localDir
* @return
* @throws ClientProtocolException
* @throws IOException
*/
public InputStream getInputStream(String urlString, String localDir,
LocalFileNameBuilder builder) throws ClientProtocolException,
IOException {

HttpParams params = new BasicHttpParams();
// add the timeout
HttpConnectionParams.setConnectionTimeout(params, TIMEOUT);
HttpConnectionParams.setSoTimeout(params, TIMEOUT);

DefaultHttpClient httpClient = new DefaultHttpClient(params);
HttpGet request = new HttpGet(urlString);
HttpResponse response = httpClient.execute(request);

if (response.getStatusLine().getStatusCode() != HttpStatus.SC_OK) {
request.abort();
return null;
}
InputStream in = response.getEntity().getContent();

String localPath = getLocalPath(urlString, localDir, builder);
// 保存到本地

File f = new File(localPath);
if (f.createNewFile()) {
FileOutputStream fo = new FileOutputStream(f);

BufferedInputStream bi = new BufferedInputStream(in);
byte[] buffer = new byte[1024 * 10];
int len = 0;
while ((len = bi.read(buffer)) > 0) {
fo.write(buffer, 0, len);
fo.flush();
}

bi.close();
fo.close();
return new FileInputStream(f);
}
return in;

}

/**
* 初始化 Bitmap参数
*/
private void initOptions() {
if (opts == null) {
opts = new BitmapFactory.Options();
opts.inPreferredConfig = Bitmap.Config.RGB_565;
opts.inSampleSize = 1;
}
}

/**
*
* @param urlString
*            网路路径
* @param localDir
*            本地存储路径 如果不为null就保存到相应目录 否则保存到 temp目录
*
* @return
*/
public Bitmap getBitmapByUrl(String urlString, String localDir,
LocalFileNameBuilder builder) {
if (TextUtils.isEmpty(urlString)) {
return null;
}

Log.v("ImageLoader", "ImageLoader load for:"+ urlString );
try {
return getBitmapFromUrl(urlString, localDir, builder);
} catch (OutOfMemoryError e) {
e.printStackTrace();
} catch (Exception e) {
Log.v(this.getClass().getSimpleName(),
"Network Exception fetchDrawable failed 1st time" + e);
try {
return getBitmapFromUrl(urlString, localDir, builder);
} catch (OutOfMemoryError es) {
es.printStackTrace();
} catch (Exception ex) {
ex.printStackTrace();
Log.v(this.getClass().getSimpleName(),
"Network Exception fetchDrawable failed 2nd time" + ex);
}
}
return null;
}

/**
* 保存网络文件到本地
*
* @param urlString
* @param localDir
* @param builder
*/
public void loadUrlTolocal(String urlString, String localDir,
LocalFileNameBuilder builder) {
String localfile = getLocalPath(urlString, localDir, builder);
File f = new File(localfile);
if (f.exists() && f.canRead()) {
return;
}

try {
InputStream in = getInputStream(urlString, localDir, builder);
in.close();
} catch (ClientProtocolException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}

/**
* 获取本地保存路径
*
* @param urlString
* @param localDir
* @return
*/
private String getLocalPath(String urlString, String localDir,
LocalFileNameBuilder builder) {
String localPath;
// 获取本地路径
if (localDir != null) {

if (builder == null) {
String fileName = MD5.md5Lower(urlString.substring(
urlString.lastIndexOf('/'), urlString.length())
+ "."
+ urlString.substring(urlString.lastIndexOf('.'),
urlString.length()));
localPath = localDir + "/" + fileName;
} else {
localPath = localDir + "/"
+ builder.getName(urlString, localDir);
}

} else {
localPath = Config.EXTERNAL_PATH + "/temp/" + MD5.md5Lower(urlString);
}
return localPath;

}

/**
* 从IN中获取bitmap
*
* @param in
* @return
*/
private Bitmap getBitmapFromInputStream(InputStream in) {
Bitmap bitmap = null;
try {
initOptions();
bitmap = BitmapFactory.decodeStream(in, null, opts);
try {
in.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
} catch (OutOfMemoryError e) {
return null;
}
return bitmap;
}

/**
* get Bitmap from the input stream
*
* @throws IOException
* @throws ClientProtocolException
*/
private Bitmap getBitmapFromUrl(String urlString, String localDir,
LocalFileNameBuilder builder) throws ClientProtocolException,
IOException {
return getBitmapFromInputStream(getInputStream(urlString, localDir,
builder));
}

/**
* 获取网络图片 不永久保存图片
*
* @param urlString
* @param defaultres
* @param progressDialog
* @param imageView1
*/
public void loadBitmapOnThread(final String urlString,
final int defaultres, final ProgressDialog progressDialog,
final ImageView imageView1) {
loadBitmapOnThread(urlString, defaultres, progressDialog, imageView1,
null);

}

/**
* 加载图片 文件名使用默认规则 默认加入到缓存中
*
* @param urlString
* @param defaultres
* @param progressDialog
* @param imageView1
* @param localDir
*/
public void loadBitmapOnThread(final String urlString,
final int defaultres, final ProgressDialog progressDialog,
final ImageView imageView1, final String localDir) {

loadBitmapOnThread(urlString, defaultres, progressDialog, imageView1,
localDir, null);
}

/**
* 加载图片 默认加入到缓存中
*
* @param urlString
* @param defaultres
* @param progressDialog
* @param imageView1
* @param localDir
* @param builder
*            本地文件名生成规则
*/

public void loadBitmapOnThread(final String urlString,
final int defaultres, final ProgressDialog progressDialog,
final ImageView imageView1, final String localDir,
final LocalFileNameBuilder builder) {

loadBitmapOnThread(urlString, defaultres, progressDialog, imageView1,
localDir, builder, true);
}

/**
*
* @author popo
*/

class IRunnable implements Callable<Bitmap> {

String url;
String localDir;
LocalFileNameBuilder localFileNameBuilder;
boolean saveToCache;
ImageView imageView;
ProgressDialog progressDialog;
int defaultres;

public IRunnable(String url, String localDir,
LocalFileNameBuilder localFileNameBuilder, boolean saveToCache,
ImageView imageView, ProgressDialog progressDialog,
int defaultres) {
this.url = url;
this.localDir = localDir;
this.localFileNameBuilder = localFileNameBuilder;
this.saveToCache = saveToCache;
this.imageView = imageView;
this.progressDialog = progressDialog;
this.defaultres = defaultres;
}

@Override
public Bitmap call() throws Exception {
Bitmap drawable = null;
drawable = getBitmapByUrl(url, localDir, localFileNameBuilder);

if (drawable != null) {
Object[] obj = new Object[] { drawable, imageView, url,
defaultres, saveToCache, progressDialog };
Message message = handler.obtainMessage(1, obj);
handler.sendMessage(message);
}
if (progressDialog != null) {
progressDialog.dismiss();
}
taskMaps.remove(url);
return drawable;

}

}

class Node {
public IRunnable runnable;
public FutureTask<Bitmap> task;
}

/**
* ConcurrentHashMap or HashTable
*/
Hashtable<String, Node> taskMaps = new Hashtable<String, Node>();

/**
* 加载图片
*
* @param urlString
* @param defaultres
* @param progressDialog
* @param imageView1
* @param localDir
*            本地缓存目录
* @param builder
*            本地文件名生成规则
* @param saveToCache
*            是否 加入到缓存
*/
public void loadBitmapOnThread(final String urlString,
final int defaultres, final ProgressDialog progressDialog,
final ImageView imageView1, final String localDir,
final LocalFileNameBuilder builder, final boolean saveToCache) {
if(imageView1 == null)
return ;
Log.v("ImageLoader"," image load for:"+urlString);

// 获取以前的Tag
String tag = (String) imageView1.getTag(R.id.img_tag);

imageView1.setTag(R.id.img_tag, urlString);
if (urlString == null || urlString.trim().equals("")) {
if (imageView1.getTag(R.id.img_tag).equals(urlString))
imageView1.setImageResource(defaultres);

if (progressDialog != null) {
progressDialog.dismiss();
}

//取消图片之前的任务
cancelTask(tag);

return;
}

// 从缓存读取
try {
Bitmap bm = getBitmapFromMemCache(urlString);
if (bm != null && !bm.isRecycled()
&& imageView1.getTag(R.id.img_tag).equals(urlString)) {
Log.v("from cache", "url:" + urlString + ",imageView:"
+ imageView1.toString());
imageView1.setImageBitmap(bm);
if (progressDialog != null) {
progressDialog.dismiss();
}
//取消图片之前的任务
cancelTask(tag);
return;
} else {
removeFromCache(urlString);
if (defaultres > 0)
imageView1.setImageResource(defaultres);

}
} catch (OutOfMemoryError e) {
e.printStackTrace();
}
final String localPath = getLocalPath(urlString, localDir, builder);
if (localPath != null) {
imageView1.setTag(R.id.localimg_tag, localPath);
}
File f = new File(localPath);
if (f.exists() && f.canRead()) {
try {
FileInputStream fi = new FileInputStream(f);
Bitmap b = getBitmapFromInputStream(fi);
if (b != null
&& imageView1.getTag(R.id.localimg_tag).equals(
localPath)) {
Log.v("from file", "url:" + urlString + ",localPath"
+ localPath);
if (saveToCache) {
if (!b.isRecycled())
addBitmapToMemoryCache(urlString, b);
}
imageView1.setImageBitmap(b);
//取消图片之前的任务
cancelTask(tag);
return;
}
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (OutOfMemoryError e) {
e.printStackTrace();
}

}

if (progressDialog != null)
progressDialog.show();

//那连个地址一样怎么办捏
//同一个变相同地址 就不做任何处理了等着吧

if(tag != null && tag.equals(urlString)){

}else{
//不一样取消之前的任务
cancelTask(tag);
final Node node = taskMaps.get(urlString);
//之前已经有图片在下载
if(node != null ){

FutureTask<Bitmap> task = new FutureTask<Bitmap>(new Callable<Bitmap>() {

@Override
public Bitmap call() throws Exception {
try {
Bitmap drawable = node.task.get();
if (drawable != null) {
Object[] obj = new Object[] { drawable, imageView1, urlString,
defaultres, saveToCache, progressDialog };
Message message = handler.obtainMessage(1, obj);
handler.sendMessage(message);
}

} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
return null;
}
});

blockingqeque.offer(task);

}else{
IRunnable runnable = new IRunnable(urlString, localDir, builder, saveToCache, imageView1, progressDialog, defaultres);
FutureTask<Bitmap> task =  new FutureTask<Bitmap>(runnable);
blockingqeque.offer(task);
Node n = new Node();
n.runnable = runnable;
n.task = task;
taskMaps.put(urlString, n);
}
}
}

/**
* 取消图片任务
* @param tag
*/
private void cancelTask(String tag) {
// 现在图片已经不需要新下载的图片了 那么取消掉吧
if(tag == null)
return;
Node node = taskMaps.get(tag);
if (node != null) {
boolean canceled = node.task.cancel(false);
if (canceled && node.task.isCancelled()) {
taskMaps.remove(tag);
}

}
}

final Handler handler = new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message message) {

ImageView imageView = (ImageView) ((Object[]) message.obj)[1];
String imgpath = (String) ((Object[]) message.obj)[2];
int defaultres = (Integer) ((Object[]) message.obj)[3];
boolean saveToCache = (Boolean) ((Object[]) message.obj)[4];
if (((Object[]) message.obj)[5] != null) {
ProgressDialog pd = (ProgressDialog) ((Object[]) message.obj)[5];
if (pd != null) {
pd.dismiss();
}
}

Log.v("NETIMAGE", "url:" + imgpath + ",imageView:" + imageView);
switch (message.what) {
case 1:
try {
Bitmap bm = null;
if (null == message.obj) {
if (defaultres > 0)
imageView.setImageResource(defaultres);
} else {
bm = (Bitmap) ((Object[]) message.obj)[0];

if (!bm.isRecycled()) {
if (imageView != null
&& imageView.getTag(R.id.img_tag) != null
&& imageView.getTag(R.id.img_tag).equals(
imgpath))

imageView.setImageBitmap(bm);
removeFromCache(imgpath);
addBitmapToMemoryCache(imgpath, bm);
} else {
if (imageView != null && defaultres > 0)
imageView.setImageResource(defaultres);
}
}
} catch (OutOfMemoryError e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}

break;
}
}

};

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: