2010-09-15 28 views
6

Tôi đang hiển thị hình ảnh và một số văn bản trong chế độ xem danh sách với bộ điều hợp. Các hình ảnh được lấy từ web, sau đó được lưu trữ cục bộ và hiển thị. Các hình ảnh đã nhỏ (60px vuông) và tôi biết kích thước của chúng, vì vậy tôi đang sử dụng advice from here suggesting I use setImageURI instead of decoding the bitmap.Tại sao ImageView.setImageURI() hoạt động trong Android 2.2 nhưng không phải 2.1?

Lớp rằng làm việc này là một phiên bản sửa đổi của mã Fedor của ImageLoader

Các chú có thể vẽ sơ khai đến ImageView đến khi hình ảnh mong muốn sẽ được tải về từ trang web, sau đó tải các tập tin lưu trữ từ sdcard. Trong Android 2.2, nó hoạt động tốt. Nó nhanh, và tôi không bị OOM treo. Trên 2.1, tuy nhiên, tôi nhận được thông báo lỗi sau:

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 

Lớp ImageLoader được như sau:

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

} 

Đây là một trong những adapter mà thực hiện ImageLoader này:

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; 
    } 



} 

Trả lời

6

tôi đã cùng một vấn đề và nó bật ra rằng 2.1 đòi hỏi tiết kiệm Uri để chuỗi như uriVaribale.getPath() ... Ví dụ:

String stringUri = imageUri.getPath(); //works 
String stringUri = imageUri.toString(); //does not work 

i.setImageURI(Uri.parse(stringUri)); 

Khi sử dụng getPath() nó dường như hoạt động trên tất cả các hệ điều hành Android.

4

SIMPLE FIX. ĐÂY LÀ đoạn I THAY ĐỔI

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); 
     } 

    } 

} 
+0

sửa lỗi tương tự nên được áp dụng cho Uri b = Uri.fromFile (f); dòng trong phương thức getUri –

Các vấn đề liên quan