¿Por qué ImageView.setImageURI () funcionaría en Android 2.2 pero no en 2.1?

Estoy mostrando imágenes y algún texto en una vista de lista con un adaptador. Las imágenes se extraen de la web, luego se almacenan en caché localmente y se muestran. Las imágenes ya son pequeñas (60px cuadrados), y sé su tamaño, así que estoy usando el consejo de aquí que sugiere que uso setImageURI en lugar de decodificar el mapa de bits .

La clase que realiza el trabajo es una versión modificada de ImageLoader de Fedor

El código adjunta un stub dibujable a la ImageView hasta que la imagen deseada se descarga desde la web, a continuación, carga el archivo en caché de la tarjeta sd. En Android 2.2 esto funciona muy bien. Es rápido, y no tengo accidentes de OOM. En 2.1, sin embargo, obtengo el siguiente error:

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 

La clase ImageLoader es la siguiente:

 /* 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(); } } 

Este es uno de los adaptadores que implementa 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; } } 

Tuve el mismo problema y resultó que 2.1 requiere salvar Uri a cadenas como uriVaribale.getPath () … ejemplo:

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

Al usar getPath () parece que funciona en todos los sistemas operativos Android.

FIX SIMPLE. AQUÍ ESTÁ EL SNIPPET QUE CAMBIÉ

 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); } } } 
  • Crear archivo de tipo android de Uri
  • ¿Cómo obtener el Uri de una imagen almacenada en el SDCARD?
  • Cómo convertir una cadena en un android.net.Uri
  • Compartir imagen de la URL a través de la aplicación de Twitter - Android
  • Obtenga la colección de nombres de parámetros de la url de Java / Android
  • Problema con URI matcher en Android
  • Cómo restaurar el archivo vcf sin utilizar la aplicación externa?
  • Error en la conexión http java.lang.IllegalArgumentException: El carácter no permitido en la consulta en el índice 76
  • Android: Creación de miniaturas de vídeo de URI de vídeo
  • Uri regresó después de ACTION_GET_CONTENT de la galería no está trabajando en setImageURI () de ImageView
  • Imagen de Uri a bytesarray
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.