Gallery从网上读取图片,可取消的多线程demo

来源:互联网 发布:异界修真淘宝店txt 编辑:程序博客网 时间:2024/04/29 18:40

应朋友要求,用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() {@Overridepublic void handleMessage(Message msg) {switch (msg.what) {case 0x110:adapter.notifyDataSetChanged();break;}super.handleMessage(msg);}};@Overrideprotected 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;}@Overrideprotected void onDestroy() {super.onDestroy();exec.shutdownNow();}@Overrideprotected 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;}@Overridepublic 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 {@Overridepublic int getCount() {return urls.size();}@Overridepublic Object getItem(int position) {return urls.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic 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,希望朋友们,能指出来,共同进步哈,谢谢

原创粉丝点击