17、网络图片加载
程序员文章站
2022-03-11 10:45:59
...
如上节,有时候需要显示网络图片,QListView的Item中或其他地方。写一个类负责将网络图片下载下来,供使用。
原理很简单,当有图片下载请求时,就新建一个线程去从网络中获取数据,并存放到一个Map中,下载完成时使用Handler去通知并在回调函数中返回图片数据。
Map使用图片的网络路径作为索引,存放图片数据Drawable,将下载好的图片数据加入到最后,并判断总数超出限制数量则将最前的去除。
为了避免一次请求图片过多,新建的线程过多,使用ThreadPoolExecutor进行管理。
加载图片的方法loadImage()传入网络图片路径、加载完毕的监听器,及两个其他参数(会在回调函数中附带,解决ListView Item中图片错位的问题)。
具体下载图片数据则直接使用Drawable.createFromStream生成Drawable。
使用如下:
效果可以用一个ImageView试一下,之后会在QListView中使用。
public class ImageLoad { private Context context; private Map<String, Drawable> imageMap; private ThreadPoolExecutor executor = null; BlockingQueue<Runnable> queue =null; private String path=Environment.getExternalStorageDirectory()+"/Dp Notes/Cache/PreImage"; private int threadMaxNum=Runtime.getRuntime().availableProcessors()>1?Runtime.getRuntime().availableProcessors():2; private int cacheMaxNum=1; private Drawable errorDrawable,loadingDrawable; @SuppressLint("NewApi") public ImageLoad(Context context){ this.context=context; imageMap=new LinkedHashMap<String, Drawable>(); queue =new ArrayBlockingQueue<Runnable>(this.threadMaxNum); executor=new ThreadPoolExecutor(this.threadMaxNum,this.threadMaxNum,1,TimeUnit.MINUTES,queue,new ThreadPoolExecutor.CallerRunsPolicy()); errorDrawable=context.getResources().getDrawable(R.drawable.ic_launcher); loadingDrawable=context.getResources().getDrawable(R.drawable.ic_launcher); // File dir=new File(this.path); // if(!dir.exists()){ // dir.mkdirs(); // } } public void setcacheMaxNum(int maxNum){ this.cacheMaxNum=maxNum; } public Drawable loadImage(final View viewParent,final int viewTag,final String imageUrl,final ImageLoadCallback callback){ if (imageMap.containsKey(imageUrl)) { Drawable drawable=imageMap.get(imageUrl); if(drawable==null){ return loadingDrawable; } else if(drawable!=errorDrawable){ return drawable; } } // int index=imageUrl.lastIndexOf("/"); // index=index>=0?index:0; // String filename=imageUrl.substring(index); // final String filepath=path+filename+".0"; // // final File mf=new File(filepath); // if(mf.exists()){ // Bitmap bitmap=BitmapFactory.decodeFile(filepath); // BitmapDrawable draw=new BitmapDrawable(context.getResources(),bitmap); // if(draw!=null){ // imageMap.put(imageUrl,draw); // chackMapSize(); // return draw; // } // } imageMap.put(imageUrl,null); final Handler handler = new Handler() { @SuppressLint("HandlerLeak") public void handleMessage(Message message) { if(callback!=null){ if(message.what==1){ callback.onSuccess((Drawable) message.obj,viewTag,viewParent); } } } }; executor.execute(new Runnable() { @Override public void run() { // TODO Auto-generated method stub URL url = null; InputStream inputStream = null; try { url = new URL(imageUrl); inputStream = url.openStream(); Drawable drawable = Drawable.createFromStream(inputStream, "src"); Message message; if(drawable==null){ drawable=errorDrawable; } message=handler.obtainMessage(1,drawable); handler.sendMessage(message); imageMap.put(imageUrl,drawable); chackMapSize(); // if(drawable!=errorDrawable){ // try { // if(!mf.exists()){ // try { // mf.createNewFile(); // } catch (IOException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } // FileOutputStream fout=new FileOutputStream(mf); // Bitmap bitmap=((BitmapDrawable)drawable).getBitmap(); // bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fout); // } catch (FileNotFoundException e) { // // TODO Auto-generated catch block // e.printStackTrace(); // } // } } catch (Exception e) { e.printStackTrace(); } finally { try { if (inputStream != null) inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } }); return loadingDrawable; } private void chackMapSize(){ if(imageMap.size()>cacheMaxNum){ for(Entry<String, Drawable> m:imageMap.entrySet()){ imageMap.remove(m.getKey()); break; } } } public interface ImageLoadCallback { public void onSuccess(Drawable drawable,int tag,View viewParent); } }
原理很简单,当有图片下载请求时,就新建一个线程去从网络中获取数据,并存放到一个Map中,下载完成时使用Handler去通知并在回调函数中返回图片数据。
Map使用图片的网络路径作为索引,存放图片数据Drawable,将下载好的图片数据加入到最后,并判断总数超出限制数量则将最前的去除。
为了避免一次请求图片过多,新建的线程过多,使用ThreadPoolExecutor进行管理。
加载图片的方法loadImage()传入网络图片路径、加载完毕的监听器,及两个其他参数(会在回调函数中附带,解决ListView Item中图片错位的问题)。
具体下载图片数据则直接使用Drawable.createFromStream生成Drawable。
使用如下:
private ImageLoad imgload; //定义类对象 imgload=new ImageLoad(activity); //构建 //合适的地方启动加载: Drawable pre=imgload.loadImage(viewparent,tagpre,data.preurl,ilcallback); if(drawable!=null){ holder.rl_data.setBackground(pre); } private ImageLoadCallback ilcallback=new ImageLoadCallback() { @SuppressLint("NewApi") @Override public void onSuccess(Drawable drawable, int tag, View viewParent) { // TODO Auto-generated method stub if(drawable!=null){ holder.rl_data.setBackground(drawable); } } };
效果可以用一个ImageView试一下,之后会在QListView中使用。
人定胜天——2017/05/21