本文只是记录一些零碎的东西
如果你看过这篇加载网络图片的文章,本篇算是对上一个的一个完善吧
每次new 一个线程,不说你也会想到这么做的坏处:
1. 每次new Thread新建对象性能差。
2. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
3. 缺乏更多功能,如定时执行、定期执行、线程中断。
然后我们要使用Java里提供给我们的线程池,先看看在java里测试
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPool {
public static void main(String[] args) {
//java.util.concurrent.ThreadPoolExecutor.ThreadPoolExecutor(int corePoolSize,
// int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 200, TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(5));
for(int i=0;i<15;i++){
MyTask myTask = new MyTask(i);
executor.execute(myTask);
System.out.println("线程池中线程数目:"+executor.getPoolSize()+",队列中等待执行的任务数目:"+
executor.getQueue().size()+",已执行完的任务数目:"+executor.getCompletedTaskCount());
}
executor.shutdown();
// 上面是我们自己创建,以下是java 提供好线程池构造函数
//创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程,线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
ExecutorService executorService1 = Executors.newCachedThreadPool();
executorService1.execute(new MyTask(100));
// 固定五个线程来执行任务,可控制线程最大并发数,超出的线程会在队列中等待
ExecutorService executorService2 = Executors.newFixedThreadPool(5);
executorService2.execute(new MyTask(200));
// 创建一个定长线程池,支持定时及周期性任务执行,延迟3秒执行
ScheduledExecutorService scheduledThreadPool3 = Executors.newScheduledThreadPool(5);
scheduledThreadPool3.schedule(new Runnable() {
@Override
public void run() {
System.out.println("delay 3 seconds");
}
}, 3, TimeUnit.SECONDS);
// 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行
ExecutorService executorService4 = Executors.newSingleThreadExecutor();
executorService4.execute(new MyTask(400));
}
}
class MyTask implements Runnable {
private int taskNum;
public MyTask(int num) {
this.taskNum = num;
}
@Override
public void run() {
System.out.println("正在执行task "+taskNum);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task "+taskNum+"执行完毕");
}
};
更改上篇文章中的代码,需要注意的是多线程公用一个对象的问题,我一开始没有注意,三张图片只显示最后一张,原来是对象的全局的,三个线程都是操作的一个ImageView,看看工具类,实测有效
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.lang.ref.SoftReference;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Matrix;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.widget.ImageView;
/**
* 根据 url 获取用户头像
*
* @author chenling0418
*
*/
public class UserImgHttp {
private static Map<String, SoftReference<Bitmap>> imageCache = new HashMap<String, SoftReference<Bitmap>>();
private static Bitmap bitmap;
private static Handler mHandler = new Handler();
// 固定五个线程来执行任务
private static ExecutorService executorService = Executors.newCachedThreadPool();
private static ImageView view;//要显示图片的控件
private static String url;//图片的网络地址
private static int degree;//图片显示时相较原图旋转的角度,即图片旋转显示
public static void setUserImg3(final ImageView view1,final String url1,final int degree1) {
//从缓存中取软引用的Bitmap对象
SoftReference<Bitmap> bitmapcache_ = imageCache.get(url1);
bitmap = null;
//取出Bitmap对象,如果由于内存不足Bitmap被回收,将取得空
if(bitmapcache_ != null){
bitmap = bitmapcache_.get();
}
if(bitmap != null){
Log.i("slack", "bitmap_ != null");
changeView(mHandler,view1,bitmap);
}else{
view = view1;
url = url1;
degree = degree1;
// Log.i("slack","url:"+url);
executorService.execute(new GetWebPic(url1, view1,bitmap, degree1));
}
}
private static void changeView(Handler handler,final ImageView view,final Bitmap bitmap) {
handler.post(
new Runnable() {
@Override
public void run() {
view.setImageBitmap( bitmap );
// Log.i("slack", "img done...");
}
});
}
public static class GetWebPic implements Runnable {
private ImageView mImageView;
private Bitmap mBitmap;
private String mUrl;// url地址
private int mDegree;// 旋转角度
public GetWebPic(String url,ImageView imageView,Bitmap bitmap,int degree){
this.mUrl = url;
this.mImageView = imageView;
this.mBitmap = bitmap;
this.mDegree = degree;
}
@Override
public void run() {
InputStream inputStream = null;
ByteArrayOutputStream out = null;
try {
// Log.i("slack", "img start..."+Thread.currentThread().getName()+mUrl);
URL localURL = new URL(mUrl);
URLConnection connection = localURL.openConnection();
HttpURLConnection httpURLConnection = (HttpURLConnection) connection;
httpURLConnection.setRequestProperty("Accept-Charset", "utf-8");
httpURLConnection.setRequestProperty("Content-Type",
"application/x-www-form-urlencoded");
if (httpURLConnection.getResponseCode() >= 300) {
Log.i("slack","error:"+httpURLConnection.getResponseCode());
throw new Exception(
"HTTP Request is not success, Response code is "
+ httpURLConnection.getResponseCode());
}
inputStream = httpURLConnection.getInputStream();
out = new ByteArrayOutputStream();
byte[] buffer=new byte[1024];
int n=0;
while ( (n=inputStream.read(buffer)) !=-1) {
out.write(buffer,0,n);
}
//本地缓存图片
out.close();
//强引用的Bitmap对象
mBitmap = BitmapFactory.decodeByteArray(out.toByteArray(), 0, out.toByteArray().length);
Matrix matrix = new Matrix();
matrix.setRotate(mDegree);
int width = mBitmap.getWidth();
int height = mBitmap.getHeight();
mBitmap = Bitmap.createBitmap(mBitmap, 0, 0, width,
height, matrix, true);
//软引用的Bitmap对象
SoftReference<Bitmap> bitmapcache = new SoftReference<Bitmap>(mBitmap);
//添加该对象到Map中使其缓存
imageCache.put(mUrl,bitmapcache);
changeView(mHandler,mImageView,mBitmap);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.i("slack","error:"+e.toString());
}finally{
try {
inputStream.close();
out.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
};
}
还有上面的缓存图片的方式,貌似更容易被垃圾回收器(GC)回收,使用LruCache,具体使用
/**
* 图片缓存技术的核心类,用于缓存所有下载好的图片,在程序内存达到设定值时会将最少最近使用的图片移除掉。
*/
private LruCache<String, Bitmap> mMemoryCache;
//获取应用程序最大可用内存
int maxMemory = (int) Runtime.getRuntime().maxMemory();
int cacheSize = maxMemory / 8;
// 设置图片缓存大小为程序最大可用内存的1/8
mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {
@Override
protected int sizeOf(String key, Bitmap bitmap) {
return bitmap.getByteCount();
}
};
/**
* 将一张图片存储到LruCache中。
*
* @param key
* LruCache的键,这里传入图片的URL地址。
* @param bitmap
* LruCache的键,这里传入从网络上下载的Bitmap对象。
*/
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemoryCache(key) == null) {
mMemoryCache.put(key, bitmap);
}
}
/**
* 从LruCache中获取一张图片,如果不存在就返回null。
*
* @param key
* LruCache的键,这里传入图片的URL地址。
* @return 对应传入键的Bitmap对象,或者null。
*/
public Bitmap getBitmapFromMemoryCache(String key) {
return mMemoryCache.get(key);
}