在请求网络时。我们经常会从服务端获取图片,下面我总结了一些图片的处理方法,希望能够帮助其他人
防止批量加载图片时出现OOM(OutOfMemory)
压缩图片
BitmapUtils 图片操作的工具类
//width 图片显示的宽度 height图片显示的高度
Bitmap loadBitmap(is, width, height){
}
Android中图片缓存的实现
Java中的引用
1>强引用 Strong References
就算出现OOM,Java虚拟机都不会销毁该引用。
2>软引用 Soft References
如果Java管理的内存趋于阈值时,GC将会销毁
一部分软引用,释放内存。
3>弱引用 Weak References
比软引用还要弱。
4>虚引用 ………..
不做了解。
SoftReference 软引用对象
SoftReference ref = new SoftReference(bitmap);
Bitmap bitmap=ref.get();
内存缓存(把图片存入内存中)
存图片 (当图片从服务端下载成功后需要存)
Map <String,SoftReference<Bitmap>> cache;
cache.put(path, new SoftReference(bitmap) );
内存中取图片
SoftReference ref=cache.get(path);
if(ref!=null){
Bitmap b=ref.get();
if(b!=null){
设置...
}
}
文件缓存(把图片存在文件里)
向文件中存图片BitmapUtils.save(bitmap, path);
从文件中读取图片
//path 文件存储路径
Bitmap BitmapUtils.loadBitmap(path);
package cn.tedu.music_player_v4.util;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.graphics.BitmapFactory.Options;
import android.os.AsyncTask;
/**
* 图片相关工具方法
*/
public class BitmapUtils {
/**
* 异步在工作线程中执行图片模糊化处理
*
* @param bitmap
* @param r
* @param callback
*/
public static void loadBluredBitmap(final Bitmap bitmap, final int r,
final BitmapCallback callback) {
new AsyncTask<String, String, Bitmap>() {
protected Bitmap doInBackground(String... params) {
Bitmap b = createBlurBitmap(bitmap, r);
return b;
}
protected void onPostExecute(Bitmap b) {
callback.onBitmapLoaded(b);
}
}.execute();
}
/**
* 传递bitmap 传递模糊半径 返回一个被模糊的bitmap
*
* @param sentBitmap
* @param radius
* @return
*/
public static Bitmap createBlurBitmap(Bitmap sentBitmap, int radius) {
Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true);
if (radius < 1) {
return (null);
}
int w = bitmap.getWidth();
int h = bitmap.getHeight();
int[] pix = new int[w * h];
bitmap.getPixels(pix, 0, w, 0, 0, w, h);
int wm = w - 1;
int hm = h - 1;
int wh = w * h;
int div = radius + radius + 1;
int r[] = new int[wh];
int g[] = new int[wh];
int b[] = new int[wh];
int rsum, gsum, bsum, x, y, i, p, yp, yi, yw;
int vmin[] = new int[Math.max(w, h)];
int divsum = (div + 1) >> 1;
divsum *= divsum;
int dv[] = new int[256 * divsum];
for (i = 0; i < 256 * divsum; i++) {
dv[i] = (i / divsum);
}
yw = yi = 0;
int[][] stack = new int[div][3];
int stackpointer;
int stackstart;
int[] sir;
int rbs;
int r1 = radius + 1;
int routsum, goutsum, boutsum;
int rinsum, ginsum, binsum;
for (y = 0; y < h; y++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
for (i = -radius; i <= radius; i++) {
p = pix[yi + Math.min(wm, Math.max(i, 0))];
sir = stack[i + radius];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rbs = r1 - Math.abs(i);
rsum += sir[0] * rbs;
gsum += sir[1] * rbs;
bsum += sir[2] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
}
stackpointer = radius;
for (x = 0; x < w; x++) {
r[yi] = dv[rsum];
g[yi] = dv[gsum];
b[yi] = dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (y == 0) {
vmin[x] = Math.min(x + radius + 1, wm);
}
p = pix[yw + vmin[x]];
sir[0] = (p & 0xff0000) >> 16;
sir[1] = (p & 0x00ff00) >> 8;
sir[2] = (p & 0x0000ff);
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[(stackpointer) % div];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi++;
}
yw += w;
}
for (x = 0; x < w; x++) {
rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0;
yp = -radius * w;
for (i = -radius; i <= radius; i++) {
yi = Math.max(0, yp) + x;
sir = stack[i + radius];
sir[0] = r[yi];
sir[1] = g[yi];
sir[2] = b[yi];
rbs = r1 - Math.abs(i);
rsum += r[yi] * rbs;
gsum += g[yi] * rbs;
bsum += b[yi] * rbs;
if (i > 0) {
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
} else {
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
}
if (i < hm) {
yp += w;
}
}
yi = x;
stackpointer = radius;
for (y = 0; y < h; y++) {
pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16)
| (dv[gsum] << 8) | dv[bsum];
rsum -= routsum;
gsum -= goutsum;
bsum -= boutsum;
stackstart = stackpointer - radius + div;
sir = stack[stackstart % div];
routsum -= sir[0];
goutsum -= sir[1];
boutsum -= sir[2];
if (x == 0) {
vmin[y] = Math.min(y + r1, hm) * w;
}
p = x + vmin[y];
sir[0] = r[p];
sir[1] = g[p];
sir[2] = b[p];
rinsum += sir[0];
ginsum += sir[1];
binsum += sir[2];
rsum += rinsum;
gsum += ginsum;
bsum += binsum;
stackpointer = (stackpointer + 1) % div;
sir = stack[stackpointer];
routsum += sir[0];
goutsum += sir[1];
boutsum += sir[2];
rinsum -= sir[0];
ginsum -= sir[1];
binsum -= sir[2];
yi += w;
}
}
bitmap.setPixels(pix, 0, w, 0, 0, w, h);
return (bitmap);
}
/**
* 通过一个网络的路径加载一张图片
*
* @param path
*/
public static void loadBitmap(Context context, final String path,
final int width, final int height, final BitmapCallback callback) {
if(path == null || path.equals("")){
callback.onBitmapLoaded(null);
return;
}
// 先去文件中找找 看看有没有下载过
String filename = path.substring(path.lastIndexOf("/") + 1);
final File file = new File(context.getCacheDir(), filename);
Bitmap bitmap = loadBitmap(file.getAbsolutePath());
if (bitmap != null) {
callback.onBitmapLoaded(bitmap);
return;
}
// 文件中没有图片 则去下载
new AsyncTask<String, String, Bitmap>() {
protected Bitmap doInBackground(String... params) {
try {
InputStream is = HttpUtils.get(path);
Bitmap b = null;
if (width == 0 && height == 0) {
b = BitmapFactory.decodeStream(is);
} else {
b = loadBitmap(is, width, height);
}
// 图片一旦下载成功 需要存入文件
save(b, file.getAbsolutePath());
return b;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
protected void onPostExecute(Bitmap bitmap) {
callback.onBitmapLoaded(bitmap);
}
}.execute();
}
/**
* 从某个路径下读取一个bitmap
*
* @param path
* @return
*/
public static Bitmap loadBitmap(String path) {
File file = new File(path);
if (!file.exists()) {
return null;
}
return BitmapFactory.decodeFile(path);
}
/**
* 保存图片
*
* @param bitmap
* @param path
* 图片的目标路径
*/
public static void save(Bitmap bitmap, String path) throws IOException {
File file = new File(path);
if (!file.getParentFile().exists()) { // 父目录不存在
file.getParentFile().mkdirs(); // 创建父目录
}
FileOutputStream os = new FileOutputStream(file);
bitmap.compress(CompressFormat.JPEG, 100, os);
}
/**
* @param is
* 数据源
* @param width
* 图片的目标宽度
* @param height
* 图片的目标高度
* @return 压缩过后的图片
*/
public static Bitmap loadBitmap(InputStream is, int width, int height)
throws IOException {
// 通过is 读取 到一个 byte[]
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buffer = new byte[1024];
int length = 0;
while ((length = is.read(buffer)) != -1) {
bos.write(buffer, 0, length);
bos.flush();
}
byte[] bytes = bos.toByteArray();
// 使用BitmapFactory获取图片的原始宽和高
Options opts = new Options();
// 仅仅加载图片的边界属性
opts.inJustDecodeBounds = true;
BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts);
// 通过目标宽和高计算图片的压缩比例
int w = opts.outWidth / width;
int h = opts.outHeight / height;
int scale = w > h ? h : w;
// 给Options属性设置压缩比例
opts.inJustDecodeBounds = false;
opts.inSampleSize = scale;
// 重新解析byte[] 获取Bitmap
return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, opts);
}
public interface BitmapCallback {
void onBitmapLoaded(Bitmap bitmap);
}
}
package cn.tedu.music_player_v4.util;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import cn.tedu.music_player_v4.R;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;
import android.widget.ListView;
/**
* 图片异步批量加载的工具类
* 自动完成 单线程下载图片
* 内存缓存 文件缓存
* @author pjy
*
*/
public class ImageLoader {
//声明用于实现内存缓存的map
private Map<String, SoftReference<Bitmap>> cache = new HashMap<String, SoftReference<Bitmap>>();
private Context context;
//声明图片下载任务集合
private List<ImageLoadTask> tasks=new ArrayList<ImageLoadTask>();
//声明用于轮循任务队列的工作线程
private Thread workThread;
private boolean isLoop=true;
private ListView listView;
// 声明handler 显示图片
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case HANDLER_LOAD_IMAGE_SUCCESS: // 图片下载成功
ImageLoadTask task = (ImageLoadTask) msg.obj;
Bitmap bitmap = task.bitmap;
// 通过listView.findViewWithTag()方法获取相应的imageView
ImageView imageView = (ImageView) listView
.findViewWithTag(task.path);
if (imageView != null) {
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(R.drawable.ic_launcher);
}
}
break;
}
}
};
public static final int HANDLER_LOAD_IMAGE_SUCCESS = 1;
public ImageLoader(Context context, ListView listView) {
this.context = context;
this.listView = listView;
//初始化并且启动workThread
workThread = new Thread(){
public void run() {
//不断轮循任务集合 一旦有任务 则获取然后执行下载操作
while(isLoop){
if(!tasks.isEmpty()){ //有任务
ImageLoadTask task=tasks.remove(0);
String path = task.path;
//下载图片
Bitmap bitmap = loadBitmap(path);
task.bitmap = bitmap;
//给imageView 设置 Bitmap
Message msg = new Message();
msg.what = HANDLER_LOAD_IMAGE_SUCCESS;
msg.obj = task;
handler.sendMessage(msg);
}else{ //没有任务 工作线程等待
try {
synchronized (workThread) {
workThread.wait();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
};
workThread.start();
}
/**
* 通过path 下载图片
*
* @param path
* @return
*/
public Bitmap loadBitmap(String path) {
try {
InputStream is = HttpUtils.get(path);
Bitmap b = BitmapUtils.loadBitmap(is, 50, 50);
// 下载成功 把b存入内存缓存中
cache.put(path, new SoftReference<Bitmap>(b));
// 存入文件缓存目录中
String filename = path.substring(path.lastIndexOf("/") + 1);
// f --> /data/data/cn.tedu.music/cache/xxxxx.jpg
File f = new File(context.getCacheDir(), filename);
BitmapUtils.save(b, f.getAbsolutePath());
return b;
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
/**
* 通过path 下载图片 并且把图片显示在相应的ImageView中
* @param imageView
* @param path
*/
public void displayImage(ImageView imageView, String imagePath){
//设置图片 从缓存中读取图片
SoftReference<Bitmap> ref=cache.get(imagePath);
if(ref!=null){
Bitmap bitmap=ref.get();
if(bitmap!=null){ //图片还没有被销毁
imageView.setImageBitmap(bitmap);
return;
}
}
//内存缓存中没有图片 则去文件缓存中读取
String filename = imagePath.substring(imagePath.lastIndexOf("/")+1);
File f = new File(context.getCacheDir(), filename);
Bitmap bitmap=BitmapUtils.loadBitmap(f.getAbsolutePath());
if(bitmap!=null){
imageView.setImageBitmap(bitmap);
//向内存缓存中再存一次
cache.put(imagePath, new SoftReference<Bitmap>(bitmap));
return;
}
// 向任务集合中添加一个图片下载任务
//给imageView设置一个tag值 用于handler中通过tag值找到imageView
imageView.setTag(imagePath);
ImageLoadTask task = new ImageLoadTask();
task.path = imagePath;
tasks.add(task);
//唤醒工作线程 赶紧起来干活
synchronized (workThread) {
workThread.notify();
}
}
/**
* 封装一个图片下载任务
*/
class ImageLoadTask {
String path; //图片路径
Bitmap bitmap; //通过路径下载成功的bitmap
}
/**
* 停止线程
*/
public void stopThread() {
isLoop = false;
synchronized (workThread) {
// 唤醒工作线程
workThread.notify();
}
}
}
时间: 2024-10-14 21:21:44