1:网络的底层环境 采用apache 的httpClient 链接池框架

2:图片缓存采用基于LRU 的算法

3:网络接口采用监听者模式

4 包含图片的OOM 处理(及时回收处理技术的应用)

package xiaogang.enif.image;


import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.HashMap;
import java.util.concurrent.RejectedExecutionException;


import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;


import xiaogang.enif.utils.HttpManager;
import xiaogang.enif.utils.IOUtils;
import xiaogang.enif.utils.LogUtils;
import xiaogang.enif.utils.LruCache;
import android.app.ActivityManager;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.graphics.Canvas;
import android.graphics.drawable.BitmapDrawable;
import android.os.AsyncTask;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.widget.ImageView;


public class CacheView extends ImageView {
private static final int DEFAULT_RES_ID = 0;
private int mDefaultImage = DEFAULT_RES_ID;


private static LruCache<String, Bitmap> mLruCache;
private static HashMap<Integer, SoftReference<Bitmap>> mResImage;


private Context mContext;
private LogUtils mLog = LogUtils.getLog(CacheView.class);


public CacheView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
}


public CacheView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);


}


public CacheView(Context context) {
super(context);
init(context);
}


private void init(Context context) {
mContext = context;


if (mLruCache == null) {
final int cacheSize = getCacheSize(context);
mLruCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
// The cache size will be measured in bytes rather than
// number of items.
return bitmap.getRowBytes() * bitmap.getHeight();
}


@Override
protected void entryRemoved(boolean evicted, String key, Bitmap oldValue,
Bitmap newValue) {
if (evicted && oldValue != null && !oldValue.isRecycled()) {
oldValue.recycle();
oldValue = null;
}
}
};
}


if (mResImage == null) {
mResImage = new HashMap<Integer, SoftReference<Bitmap>>();
}
}


@Override
protected void onDraw(Canvas canvas) {
BitmapDrawable drawable = (BitmapDrawable)getDrawable();
if (drawable == null) {
setDefaultImage();
} else {
if (drawable.getBitmap() == null || drawable.getBitmap().isRecycled()) {
setDefaultImage();
}
}
try {
super.onDraw(canvas);
} catch(RuntimeException ex) {


}
}


public void setImageUrl(String url, int resId) {
setTag(url);
Bitmap bitmap = getBitmapFromCache(url);
if (bitmap == null || bitmap.isRecycled()) {
mDefaultImage = resId;
setDefaultImage();
try {
new DownloadTask().execute(url);
} catch (RejectedExecutionException e) {
// do nothing, just keep not crash
}
} else {
setImageBitmap(bitmap);
}
}


private void setDefaultImage() {
if (mDefaultImage != DEFAULT_RES_ID) {
setImageBitmap(getDefaultBitmap(mContext));
}
}


private Bitmap getDefaultBitmap(Context context) {
SoftReference<Bitmap> loading = mResImage.get(mDefaultImage);
if (loading == null || loading.get() == null || loading.get().isRecycled()) {
loading = new SoftReference<Bitmap>(BitmapFactory.decodeResource(
context.getResources(), mDefaultImage));
mResImage.put(mDefaultImage, loading);
}
return loading.get();
}


private class DownloadTask extends AsyncTask<String, Void, Bitmap> {
private String mParams;


@Override
public Bitmap doInBackground(String... params) {
mParams = params[0];
final Bitmap bm = download(mParams);
addBitmapToCache(mParams, bm);
return bm;
}


@Override
public void onPostExecute(Bitmap bitmap) {
String tag = (String)getTag();
if (!TextUtils.isEmpty(tag) && tag.equals(mParams)) {
if (bitmap != null) {
setImageBitmap(bitmap);
}
}
}
};


/*
* An InputStream that skips the exact number of bytes provided, unless it
* reaches EOF.
*/
static class FlushedInputStream extends FilterInputStream {
public FlushedInputStream(InputStream inputStream) {
super(inputStream);
}


@Override
public long skip(long n) throws IOException {
long totalBytesSkipped = 0L;
while (totalBytesSkipped < n) {
long bytesSkipped = in.skip(n - totalBytesSkipped);
if (bytesSkipped == 0L) {
int b = read();
if (b < 0) {
break; // we reached EOF
} else {
bytesSkipped = 1; // we read one byte
}
}
totalBytesSkipped += bytesSkipped;
}
return totalBytesSkipped;
}
}


private Bitmap download(String url) {
InputStream in = null;
HttpEntity entity = null;
Bitmap bmp = null;
try {
final HttpGet get = new HttpGet(url);
final HttpResponse response = HttpManager.execute(mContext, get);
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
entity = response.getEntity();
in = entity.getContent();
try {
bmp = getDecodeBitmap(in, url);
} catch (OutOfMemoryError err) {
Runtime.getRuntime().gc();
bmp = getDecodeBitmap(in, url);
}
} else {
get.abort();
return bmp;
}
addBitmapToCache(url, bmp);
} catch (IOException e) {
return bmp;
} finally {
IOUtils.closeStream(in);
}
return bmp;
}


private final Bitmap getDecodeBitmap(InputStream in, String url) {
Options options = new Options();
options.inPurgeable = true;
options.inInputShareable = true;
return BitmapFactory.decodeStream(new FlushedInputStream(in), null, options);
}


private final void addBitmapToCache(String url, Bitmap bitmap) {
if (bitmap != null) {
mLruCache.put(url, bitmap);
Runtime.getRuntime().gc();
}
}


private final Bitmap getBitmapFromCache(String url) {
return mLruCache.get(url);
}


private int getCacheSize(Context context) {
// According to the phone memory, set a proper cache size for LRU cache
// dynamically.
final ActivityManager am = (ActivityManager)context
.getSystemService(Context.ACTIVITY_SERVICE);
final int memClass = am.getMemoryClass();


int cacheSize;
if (memClass <= 24) {
cacheSize = (memClass << 20) / 24;
} else if (memClass <= 36) {
cacheSize = (memClass << 20) / 18;
} else if (memClass <= 48) {
cacheSize = (memClass << 20) / 12;
} else {
cacheSize = (memClass << 20) >> 3;
}
mLog.debug("cacheSize == "+cacheSize);
System.out.println("cacheSize == "+cacheSize);
return cacheSize;
}


public static void recycle() {
if (mLruCache != null && !mLruCache.isEmpty()) {
mLruCache.evictAll();
mLruCache = null;
}


if (mResImage != null) {
for (SoftReference<Bitmap> reference : mResImage.values()) {
Bitmap bitmap = reference.get();
if (bitmap != null && !bitmap.isRecycled()) {
bitmap.recycle();
bitmap = null;
}
}
mResImage = null;
}
}
}




说明:

1)entryRemoved 在做Bitmap recyle 的时候的三个条件缺一不可

2)onDraw 里面判断图片是否被回收,如果回收 需要设置默认的图片

3)add bitmap 到cache 的时候 Runtime.getRuntime().gc 的调用

转载http://blog.csdn.net/androidzhaoxiaogang/article/details/8211649


更多相关文章

  1. Android实现图片文字轮播特效
  2. 2018-06-15 Android加载GIF图片的两种方式
  3. Android-->Android(安卓)原生支持圆角图片,圆角ImageView
  4. Android(安卓)如何将Canvas上绘制的内容保存成本地图片
  5. Android原生分享图片和视频
  6. Android(安卓)Activity被回收后的处理
  7. Android(安卓)WebView怎么样嵌套Html
  8. android 实现图片的边框
  9. Android异步加载

随机推荐

  1. Android中JNI的使用
  2. Android客户端程序员的一些思考
  3. Android多进程之Binder的意外死亡及权限
  4. Android(安卓)创建与解析XML(六)—— 比较
  5. 【Android(安卓)笔记 五】 Android(安卓)
  6. Android的风暴前夕
  7. 面向UDP的Android——PC双向通信(二):实现An
  8. 有关Android手机软件详细分析
  9. 深入解读Linux与Android的相互关系
  10. 爱Android更要懂Android