【问题标题】:Why would ImageView.setImageURI() work in Android 2.2 but not 2.1?为什么 ImageView.setImageURI() 可以在 Android 2.2 中工作而不是 2.1?
【发布时间】:2010-09-15 18:19:50
【问题描述】:

我正在使用适配器在列表视图中显示图像和一些文本。图像是从网络上提取的,然后在本地缓存并显示。图片已经很小(60px 正方形),而且我知道它们的大小,所以我使用advice from here suggesting I use setImageURI instead of decoding the bitmap

完成这项工作的类是 Fedor 的 ImageLoader 的修改版本

代码将一个可绘制的存根附加到 ImageView,直到从 Web 下载所需的图像,然后从 sdcard 加载缓存的文件。在 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, Activity activity, ImageView imageView, 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, imageView, 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(), activity, holder.imgColorImg, 84);
        return convertView;


    }

    class ViewHolder{
        TextView txtName;
        //TextView txtUser;
        ImageView imgColorImg;
    }



}

【问题讨论】:

    标签: android uri imageview


    【解决方案1】:

    我遇到了同样的问题,结果发现 2.1 需要将 Uri 保存为字符串作为 uriVaribale.getPath()... 示例:

    String stringUri = imageUri.getPath(); //works
    String stringUri = imageUri.toString(); //does not work
    
    i.setImageURI(Uri.parse(stringUri));
    

    使用 getPath() 时,它似乎适用于所有 Android 操作系统。

    【讨论】:

      【解决方案2】:

      简单修复。这是我更改的代码段

      class UriDisplayer implements Runnable {
              public static final String SPINNER_IMAGELOADER = "SPINNER_IMAGELOADER_UriDisplayer";
      
          Uri uri;
          ImageView imageView;
      
          public UriDisplayer(Uri u, ImageView i) {
              uri = u;
              imageView = i;
          }
      
          public void run() {
              Log.d(SPINNER_IMAGELOADER, "rui displayer using uri path: " + uri.getPath());
              File f = new File(uri.getPath());
              Log.d(SPINNER_IMAGELOADER, "file: " + f);
              if (f.exists()) {
                  //imageView.setImageURI(uri);
                  //FIX DO IT THIS WAY
                  imageView.setImageURI(Uri.parse(f.toString()));
              } else {
                  imageView.setImageResource(stub_id);
              }
      
          }
      
      }
      

      【讨论】:

      • 同样的修复应该应用于 Uri b = Uri.fromFile(f); getUri 方法中的一行
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多