应朋友要求,用BlockingQueue,Executors写了一个线程竞争较小的demo,从网络上读取图片,然后存于本地。
当Gallery设置图片的时候,首先从缓存读取,若缓存不存在图片,则从SD卡上读取,若SD卡上不存在,则从网络获取图片,经过一整天的代码编写,重构后代码如下:
package net.liuyx.test;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Display;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Gallery;
import android.widget.ImageView;
import android.widget.Toast;
public class Main extends Activity {
private List<String> urls = new ArrayList<String>();
private Map<Integer, Bitmap> adminImages = new HashMap<Integer, Bitmap>();
private Map<Integer, Bitmap> syncGalleryImgs = new ConcurrentHashMap<Integer, Bitmap>();
private BlockingQueue<Bitmap> putInSDcardQueue;
private ExecutorService exec;
private GalleryAdapter adapter;
private Future<?> downloadFuture = null;
private ImgState state = ImgState.INTERNET;
private enum ImgState {
INTERNET {
void print() {
Log.v("liuyx", "既不存在于本地SD卡上,也不存在于本地内存上,需要您下载");
}
},
CACHE {
void print() {
Log.v("liuyx", "存在本地内存上");
}
},
SDCARD {
void print() {
Log.v("liuyx", "存在SD卡上");
}
};
abstract void print();
}
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0x110:
adapter.notifyDataSetChanged();
break;
}
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initGallery();
initUrls();
initAdminImgs();
if (state == ImgState.INTERNET)
downloadImgs();
putInSDcardQueue = new ArrayBlockingQueue<Bitmap>(urls.size());
}
/**
* 初始化Gallery,设置Adapter
*/
private void initGallery() {
Gallery gallery = (Gallery) findViewById(R.id.gallery);
adapter = new GalleryAdapter();
gallery.setAdapter(adapter);
}
/**
* 若图片还没有从网上下载完成,初始化默认显示图片(这里设置为android自带的默认图片)
*/
public void initAdminImgs() {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
R.drawable.ic_launcher);
for (int i = 0; i < urls.size(); i++) {
adminImages.put(i++, bitmap);
}
}
/**
* 将需要下载的URL添加到List容器内
*/
private void initUrls() {
urls.add("http://fujian.xabbs.com/forum/201109/02/160646nn9hjjiimixvkxhe.jpg");
urls.add("http://img1.cache.netease.com/catchpic/A/A9/A9D98040B397C366AE93E67871346561.jpg");
urls.add("http://new.aliyiyao.com/UpFiles/Image/2011/01/13/nc_129393721364387442.jpg");
urls.add("http://i1.sinaimg.cn/ent/m/c/2010-01-18/U1819P28T3D2847679F326DT20100118115712.jpg");
urls.add("http://comic.sinaimg.cn/2011/0824/U5237P1157DT20110824161051.jpg");
}
/**
* 使用Executors框架开启线程下载图片
*/
private void downloadImgs() {
exec = Executors.newCachedThreadPool();
cancel();
for (int i = 0; i < urls.size(); i++) {
downloadFuture = exec.submit(new DownloadImgTask(urls.get(i), i));
}
state = ImgState.CACHE;
}
@Override
protected void onDestroy() {
super.onDestroy();
exec.shutdownNow();
}
@Override
protected void onPause() {
super.onPause();
cancel();
}
private void cancel() {
Future<?> newFuture = downloadFuture;
if (newFuture != null)
downloadFuture.cancel(true);
}
private class DownloadImgTask implements Runnable {
final String uri;
final int index;
DownloadImgTask(String uri, int index) {
this.uri = uri;
this.index = index;
}
@Override
public void run() {
InputStream in = null;
try {
in = getImgInputStream();
final Bitmap bitmap = BitmapFactory.decodeStream(in);
syncGalleryImgs.put(index, bitmap);
sendMsg();
putInSdcard(in, bitmap);
} catch (IOException e) {
Log.v("liuyx", "the " + index + " imgs has not download!");
} finally {
closeInStream(in);
}
}
/**
* 将bitmap放在BlockingQueue中
*
* @param bitmap
*/
private void putInSdcardToQueue(Bitmap bitmap) {
try {
putInSDcardQueue.put(bitmap);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void putInSdcard(InputStream in, Bitmap bitmap)
throws FileNotFoundException {
if (!isSDCardExist()) {
Toast.makeText(Main.this, "SD卡不存在,请重新确认", 1).show();
Log.v("liuyx", "SD卡不存在,请重新确认");
return;
}
putInSdcardToQueue(bitmap);
saveFiletoSDcard(in);
if (state != ImgState.CACHE)
state = ImgState.SDCARD;
}
private boolean isSDCardExist() {
return ((Environment.getExternalStorageState() != null) && !Environment
.getExternalStorageState().equals(""));
}
private void saveFiletoSDcard(InputStream in) {
try {
File file = prepareFileInSDcard();
saveFiletoSDcard(in, file);
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
*
* @param in
* @param file
* @throws IOException
* @throws InterruptedException
*/
private void saveFiletoSDcard(InputStream in, File file)
throws IOException, InterruptedException {
Bitmap bitmap = putInSDcardQueue.take();
final OutputStream out = new FileOutputStream(file);
final BufferedOutputStream bos = new BufferedOutputStream(out);
byte[] buffer = new byte[1024];
int len = 0;
while ((len = in.read(buffer)) != -1) {
bos.write(buffer, 0, len);
}
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, bos);
bos.flush();
bos.close();
in.close();
}
/**
* 为保存的文件取个名字
*
* @return
*/
private File prepareFileInSDcard() {
File dir = Environment.getExternalStorageDirectory();
String path = dir.getAbsolutePath() + "/images/";
File file;
synchronized (this) {
String fileName = path + getImgNameInSDcard();
file = new File(fileName);
}
return file;
}
private String getImgNameInSDcard() {
return "image" + index + ".jpg";
}
private InputStream getImgInputStream() throws IOException {
final URL url = new URL(uri);
final HttpURLConnection conn = (HttpURLConnection) url
.openConnection();
conn.setRequestMethod("GET");
conn.connect();
return conn.getInputStream();
}
private void closeInStream(InputStream in) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
private void sendMsg() {
mHandler.sendEmptyMessage(0x110);
}
}
private Bitmap bitmapForSDCard = null;
class GalleryAdapter extends BaseAdapter {
@Override
public int getCount() {
return urls.size();
}
@Override
public Object getItem(int position) {
return urls.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView iv = new ImageView(getApplicationContext());
iv.setLayoutParams(new Gallery.LayoutParams(getWidth(), getHeight()));
setImgForAdapter(iv, position);
return iv;
}
private void setImgForAdapter(ImageView iv, int position) {
switch (state) {
case CACHE:
iv.setImageBitmap(getBitmap(position));
break;
case SDCARD:
iv.setImageBitmap(bitmapForSDCard);
break;
case INTERNET:
break;
default:
iv.setImageBitmap(getDefaultImg(position));
break;
}
// if (isGalleryImgExistAtCache(position)) {
// iv.setImageBitmap(getBitmap(position));
// } else if (isGalleryImgExistAtSDcard(position))
// iv.setImageBitmap(bitmapForSDCard);
// else {
// iv.setImageBitmap(getDefaultImg(position));
// }
}
}
/**
*
* @param position
* @return 缓存里的默认图片
*/
private Bitmap getDefaultImg(int position) {
return adminImages.get(position);
}
/**
*
* @param position
* @return 判断缓存是否存在图片
*/
// private boolean isGalleryImgExistAtCache(int position) {
// Log.v("liuyx", "从内存上读取");
// Bitmap bitmap = syncGalleryImgs.get(position);
// return bitmap != null;
// }
/**
*
* @param position
* @return 判断图片是否在SD卡上
*/
// private boolean isGalleryImgExistAtSDcard(int position) {
// Log.v("liuyx", "从SD卡上读取");
// String fileName = Environment.getExternalStorageDirectory()
// .getAbsolutePath() + "/image/" + "iamge" + position + ".jpg";
// FileInputStream in = getInputStream(fileName);
// bitmapForSDCard = BitmapFactory.decodeStream(in);
// return bitmapForSDCard != null;
// }
/**
*
* @param fileName
* SD卡上的文件名称
* @return 返回该文件的输入流
*/
// private FileInputStream getInputStream(String fileName){
// FileInputStream in = null;
// try {
// in = new FileInputStream(new File(fileName));
// } catch (FileNotFoundException e) {
// e.printStackTrace();
// }
// return in;
// }
private Bitmap getBitmap(int position) {
return syncGalleryImgs.get(position);
}
private Display getDisplay() {
Display display = Main.this.getWindowManager().getDefaultDisplay();
return display;
}
private int getWidth() {
return getDisplay().getWidth();
}
private int getHeight() {
return getDisplay().getHeight();
}
}
代码应该算是比较简洁,可能有点小bug,希望朋友们,能指出来,共同进步哈,谢谢