我正在使用适配器在列表视图中显示图像和一些文本.图像从Web中提取,然后在本地缓存并显示.图像已经很小(60px方形),我知道它们的大小,所以我使用的是
advice from here suggesting I use setImageURI instead of decoding the bitmap.
完成这项工作的课程是Fedor ImageLoader的修改版本
代码将一个可绘制的存根附加到ImageView,直到从Web下载所需的图像,然后从SD卡加载缓存的文件.在Android 2.2中,这很好用.这很快,我没有OOM崩溃.但是在2.1上,我收到以下错误:
- 09-15 11:04:52.993: INFO/System.out(240): resolveUri Failed on bad bitmap uri: file:///sdcard/android/data/com.example.myapp/cache/4164137
ImageLoader类如下:
- /*
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License,Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
- http://www.apache.org/licenses/LICENSE-2.0
- Unless required by applicable law or agreed to in writing,software distributed under the License is distributed on an
- "AS IS" BASIS,WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND,either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
- */
- public class ImageLoader {
- //the simplest in-memory cache implementation. This should be replaced with something like SoftReference or BitmapOptions.inPurgeable(since 1.6)
- private HashMap<String,Uri> cache=new HashMap<String,Uri>();
- private File cacheDir;
- public ImageLoader(Context context){
- //Make the background thead low priority. This way it will not affect the UI performance
- photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1);
- //Find the dir to save cached images
- if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
- cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"Android/data/com.droidicon.launcherproicons/cache/");
- else
- cacheDir=context.getCacheDir();
- if(!cacheDir.exists())
- cacheDir.mkdirs();
- }
- final int stub_id=R.drawable.loading;
- public void DisplayImage(String url,Activity activity,ImageView imageView,int scaleSize)
- {
- if(cache.containsKey(url))
- imageView.setImageURI(cache.get(url));
- else
- {
- queuePhoto(url,activity,imageView,scaleSize);
- imageView.setImageResource(stub_id);
- }
- }
- private void queuePhoto(String url,int scaleSize)
- {
- //This ImageView may be used for other images before. So there may be some old tasks in the queue. We need to discard them.
- photosQueue.Clean(imageView);
- PhotoToLoad p=new PhotoToLoad(url,scaleSize);
- synchronized(photosQueue.photosToLoad){
- photosQueue.photosToLoad.push(p);
- photosQueue.photosToLoad.notifyAll();
- }
- //start thread if it's not started yet
- if(photoLoaderThread.getState()==Thread.State.NEW)
- photoLoaderThread.start();
- }
- private Uri getUri(String url,int scaleSize){
- if(url != ""){
- //I identify images by hashcode. Not a perfect solution,good for the demo.
- // try{
- String filename=String.valueOf(url.hashCode());
- File f=new File(cacheDir,filename);
- //from SD cache
- if(f.exists()){
- Uri b = Uri.fromFile(f);
- System.out.println(f.toString());
- return b;
- }
- //from web
- try {
- Uri bitmap=null;
- InputStream is=new URL(url).openStream();
- OutputStream os = new FileOutputStream(f);
- Utils.CopyStream(is,os);
- os.close();
- bitmap = Uri.fromFile(f);
- System.out.println(f.toString());
- return bitmap;
- } catch (Exception ex){
- ex.printStackTrace();
- return null;
- }
- } else {
- return null;
- }
- }
- //Task for the queue
- private class PhotoToLoad
- {
- public String url;
- public ImageView imageView;
- public int scaleSize;
- public PhotoToLoad(String u,ImageView i,int ss){
- url=u;
- imageView=i;
- scaleSize=ss;
- }
- }
- PhotosQueue photosQueue=new PhotosQueue();
- public void stopThread()
- {
- photoLoaderThread.interrupt();
- }
- //stores list of photos to download
- class PhotosQueue
- {
- private Stack<PhotoToLoad> photosToLoad=new Stack<PhotoToLoad>();
- //removes all instances of this ImageView
- public void Clean(ImageView image)
- {
- for(int j=0 ;j<photosToLoad.size();){
- if(photosToLoad.get(j).imageView==image)
- photosToLoad.remove(j);
- else
- ++j;
- }
- }
- }
- class PhotosLoader extends Thread {
- public void run() {
- try {
- while(true)
- {
- //thread waits until there are any images to load in the queue
- if(photosQueue.photosToLoad.size()==0)
- synchronized(photosQueue.photosToLoad){
- photosQueue.photosToLoad.wait();
- }
- if(photosQueue.photosToLoad.size()!=0)
- {
- PhotoToLoad photoToLoad;
- synchronized(photosQueue.photosToLoad){
- photoToLoad=photosQueue.photosToLoad.pop();
- }
- Uri bmp=getUri(photoToLoad.url,photoToLoad.scaleSize);
- cache.put(photoToLoad.url,bmp);
- if(((String)photoToLoad.imageView.getTag()).equals(photoToLoad.url)){
- UriDisplayer bd=new UriDisplayer(bmp,photoToLoad.imageView);
- Activity a=(Activity)photoToLoad.imageView.getContext();
- a.runOnUiThread(bd);
- }
- }
- if(Thread.interrupted())
- break;
- }
- } catch (InterruptedException e) {
- //allow thread to exit
- }
- }
- }
- PhotosLoader photoLoaderThread=new PhotosLoader();
- class UriDisplayer implements Runnable
- {
- Uri uri;
- ImageView imageView;
- public UriDisplayer(Uri u,ImageView i){uri=u;imageView=i;}
- public void run() {
- File f = new File(uri.getPath());
- if(f.exists()){
- imageView.setImageURI(uri);
- } else {
- imageView.setImageResource(stub_id);
- }
- }
- }
- public void clearCache() {
- //clear memory cache
- cache.clear();
- //clear SD cache
- File[] files=cacheDir.listFiles();
- for(File f:files)
- f.delete();
- }
- }
以下是实现此ImageLoader的适配器之一:
- public class ColorAdapter extends ArrayAdapter<Color> {
- private Activity activity;
- private int resource;
- private String response;
- private Context context;
- public ImageLoader imageLoader;
- public ColorAdapter(Activity a,Context context,int resource,List<Color> items){
- super(context,resource,items);
- this.resource=resource;
- imageLoader=new ImageLoader(context);
- activity = a;
- }
- @Override
- public View getView(int position,View convertView,ViewGroup parent){
- Color color = getItem(position);
- String minflater = Context.LAYOUT_INFLATER_SERVICE;
- LayoutInflater inflater;
- inflater = (LayoutInflater)getContext().getSystemService(minflater);
- ViewHolder holder;
- if(convertView==null){
- convertView = inflater.inflate(R.layout.listcolors,parent,false);
- holder=new ViewHolder();
- holder.txtName=(TextView)convertView.findViewById(R.id.txtName);
- //holder.txtUser=(TextView)convertView.findViewById(R.id.txtUser);
- holder.imgColorImg=(ImageView)convertView.findViewById(R.id.imgColorImg);
- convertView.setTag(holder);
- }
- else
- holder=(ViewHolder)convertView.getTag();
- holder.txtName.setText(color.getName());
- //holder.txtUser.setText(dock.getUser());
- holder.imgColorImg.setTag(color.getIconURL());
- imageLoader.DisplayImage(color.getIconURL(),holder.imgColorImg,84);
- return convertView;
- }
- class ViewHolder{
- TextView txtName;
- //TextView txtUser;
- ImageView imgColorImg;
- }
- }
解决方法
我有同样的问题,事实证明,2.1需要将Uri保存为字符串为uriVaribale.getPath()…示例:
- String stringUri = imageUri.getPath(); //works
- String stringUri = imageUri.toString(); //does not work
- i.setImageURI(Uri.parse(stringUri));
当使用getPath()时,它似乎适用于所有Android操作系统.