应朋友要求,用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,希望朋友们,能指出来,共同进步哈,谢谢