延迟加载负载将图像绑定到同一活动中多个列表视图中的错误视图

时间:2012-02-01 19:12:26

标签: android listview lazy-loading

我正在使用延迟加载类Imageloader从Web服务器获取图像,我在同一个活动中有大约3个Listviews,由于某种原因,其中一个listviews以错误的方式绑定图像。我想加载我的活动然后启动加载每个列表视图的图像。这有什么有效的方法吗? Lazyload曾经工作过......我怎么能指出每个视图应该加载到每个图像?任何帮助,将不胜感激 :)

public class ImageLoader {
    private HashMap<String, Bitmap> cache=new HashMap<String, Bitmap>();
    private RotateAnimation rotate=null;
    private String MainDirectory=".Beirut.com";
    private String Directory=".images";
    private File cacheDir;

    public ImageLoader(Context context){
        //Make the background thread low priority. This way it will not affect the UI performance
        photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1);

      //checking if the main Directory exist?
        if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
            cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),MainDirectory);
        else
            cacheDir=context.getCacheDir();
        if(!cacheDir.exists())
            cacheDir.mkdirs();

        //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(),MainDirectory+"/"+Directory);
        else
            cacheDir=context.getCacheDir();
        if(!cacheDir.exists())
            cacheDir.mkdirs();
    }

    final int stub_id=R.drawable.refresh_resized_silver;
    public void DisplayImage(String url, Activity activity, ImageView imageView)
    {
        //Log.e("Image to load",url);
        rotate=new RotateAnimation(0f, 360f, 
                Animation.RELATIVE_TO_SELF,0.5f, 
                Animation.RELATIVE_TO_SELF,0.5f);
        rotate.setDuration(1000L);
        rotate.setRepeatMode(Animation.INFINITE);
        rotate.setRepeatCount(Animation.INFINITE);
        imageView.setImageResource(stub_id);
        imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);
        //imageView.setBackgroundResource(stub_id);
        imageView.startAnimation(rotate);
        if(cache.containsKey(url)){
            imageView.setImageBitmap(cache.get(url));
            imageView.invalidate();
            imageView.setScaleType(ScaleType.CENTER_INSIDE);
            imageView.clearAnimation();
            //Log.e("Animation","Cleared");

        }
        else
        {
            queuePhoto(url, activity, imageView);
        }    
    }

    private void queuePhoto(String url, Activity activity, ImageView imageView)
    {
        //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);
        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();
    }
    public static Bitmap loadImageFromUrl(String url) {     
        InputStream inputStream;
        Bitmap b;      
        try {           
            if(url.contains(" ")){                 
                url=url.replace(" ", "%20");                   
            }
            //Log.e("Error link",url);
            inputStream = (InputStream) new URL(url).getContent();             
            BitmapFactory.Options bpo=  new BitmapFactory.Options();             
            bpo.inJustDecodeBounds = true;             
            bpo.inJustDecodeBounds = false;               
            if(bpo.outWidth>400){              
                bpo.inSampleSize = 1;              
                b=BitmapFactory.decodeStream(inputStream, null,bpo );     
            }else{
                bpo.inSampleSize=1;
                b=BitmapFactory.decodeStream(inputStream, null,bpo );
            }
            return  b;     
        }catch (IOException e) {
            throw new RuntimeException(e);         
        } 
    }

    private Bitmap getBitmap(String url) 
    {
        //I identify images by hashcode. Not a perfect solution, good for the demo.
        String filename=String.valueOf(url.hashCode());
        File f=new File(cacheDir, filename);

        //from SD cache
        Bitmap b = decodeFile(f);
        if(b!=null){
            return b;
        }

        //from web
        try {
            Bitmap bitmap=null;
            InputStream is=new URL(url).openStream();
            OutputStream os = new FileOutputStream(f);
            Utils.CopyStream(is, os);
            os.close();
            bitmap = decodeFile(f);
            //bitmap=loadImageFromUrl(url);
            return bitmap;
        } catch (Exception ex){
           ex.printStackTrace();
           return null;
        }
    }

    //decodes image and scales it to reduce memory consumption
    private Bitmap decodeFile(File f){
        try {
            //decode image size
            BitmapFactory.Options o = new BitmapFactory.Options();
            o.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(new FileInputStream(f),null,o);

            //Find the correct scale value. It should be the power of 2.
            final int REQUIRED_SIZE=300;
            int width_tmp=o.outWidth, height_tmp=o.outHeight;
            int scale=1;
            while(true){
                if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                    break;
                width_tmp/=2;
                height_tmp/=2;
                scale*=2;
            }

            //decode with inSampleSize
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize=scale;

            try{
                return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);    
            }catch(FileNotFoundException e){
                return null;
            }
        } catch (FileNotFoundException e) {}
        return null;
    }

    //Task for the queue
    private class PhotoToLoad
    {
        public String url;
        public ImageView imageView;
        public PhotoToLoad(String u, ImageView i){
            url=u; 
            imageView=i;
        }
    }

    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();
                        }
                        Bitmap bmp=getBitmap(photoToLoad.url);
                        cache.put(photoToLoad.url, bmp);
                        Object tag=photoToLoad.imageView.getTag();
                        if(tag!=null && ((String)tag).equals(photoToLoad.url)){
                            BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad.imageView);
                            Activity a=(Activity)photoToLoad.imageView.getContext();
                            a.runOnUiThread(bd);
                        }
                    }
                    if(Thread.interrupted())
                        break;
                }
            } catch (InterruptedException e) {
            }
        }
    }

    PhotosLoader photoLoaderThread=new PhotosLoader();

    class BitmapDisplayer implements Runnable
    {
        Bitmap bitmap;
        ImageView imageView;
        public BitmapDisplayer(Bitmap b, ImageView i){bitmap=b;imageView=i;}
        public void run()
        {
            if(bitmap!=null)
                imageView.setImageBitmap(bitmap);
            else
                imageView.setImageResource(stub_id);
            BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable();
            drawable.setAntiAlias(true);
            imageView.setScaleType(ScaleType.CENTER_INSIDE);
            imageView.clearAnimation();
            //Log.e("Animation","Cleared");
        }
    }

    public void clearCache() {
        cache.clear();

        //clear SD cache
        File[] files=cacheDir.listFiles();
        for(File f:files)
            f.delete();
    }

}

public class ImageLoader { private HashMap<String, Bitmap> cache=new HashMap<String, Bitmap>(); private RotateAnimation rotate=null; private String MainDirectory=".Beirut.com"; private String Directory=".images"; private File cacheDir; public ImageLoader(Context context){ //Make the background thread low priority. This way it will not affect the UI performance photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1); //checking if the main Directory exist? if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED)) cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),MainDirectory); else cacheDir=context.getCacheDir(); if(!cacheDir.exists()) cacheDir.mkdirs(); //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(),MainDirectory+"/"+Directory); else cacheDir=context.getCacheDir(); if(!cacheDir.exists()) cacheDir.mkdirs(); } final int stub_id=R.drawable.refresh_resized_silver; public void DisplayImage(String url, Activity activity, ImageView imageView) { //Log.e("Image to load",url); rotate=new RotateAnimation(0f, 360f, Animation.RELATIVE_TO_SELF,0.5f, Animation.RELATIVE_TO_SELF,0.5f); rotate.setDuration(1000L); rotate.setRepeatMode(Animation.INFINITE); rotate.setRepeatCount(Animation.INFINITE); imageView.setImageResource(stub_id); imageView.setScaleType(ImageView.ScaleType.CENTER_INSIDE); //imageView.setBackgroundResource(stub_id); imageView.startAnimation(rotate); if(cache.containsKey(url)){ imageView.setImageBitmap(cache.get(url)); imageView.invalidate(); imageView.setScaleType(ScaleType.CENTER_INSIDE); imageView.clearAnimation(); //Log.e("Animation","Cleared"); } else { queuePhoto(url, activity, imageView); } } private void queuePhoto(String url, Activity activity, ImageView imageView) { //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); 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(); } public static Bitmap loadImageFromUrl(String url) { InputStream inputStream; Bitmap b; try { if(url.contains(" ")){ url=url.replace(" ", "%20"); } //Log.e("Error link",url); inputStream = (InputStream) new URL(url).getContent(); BitmapFactory.Options bpo= new BitmapFactory.Options(); bpo.inJustDecodeBounds = true; bpo.inJustDecodeBounds = false; if(bpo.outWidth>400){ bpo.inSampleSize = 1; b=BitmapFactory.decodeStream(inputStream, null,bpo ); }else{ bpo.inSampleSize=1; b=BitmapFactory.decodeStream(inputStream, null,bpo ); } return b; }catch (IOException e) { throw new RuntimeException(e); } } private Bitmap getBitmap(String url) { //I identify images by hashcode. Not a perfect solution, good for the demo. String filename=String.valueOf(url.hashCode()); File f=new File(cacheDir, filename); //from SD cache Bitmap b = decodeFile(f); if(b!=null){ return b; } //from web try { Bitmap bitmap=null; InputStream is=new URL(url).openStream(); OutputStream os = new FileOutputStream(f); Utils.CopyStream(is, os); os.close(); bitmap = decodeFile(f); //bitmap=loadImageFromUrl(url); return bitmap; } catch (Exception ex){ ex.printStackTrace(); return null; } } //decodes image and scales it to reduce memory consumption private Bitmap decodeFile(File f){ try { //decode image size BitmapFactory.Options o = new BitmapFactory.Options(); o.inJustDecodeBounds = true; BitmapFactory.decodeStream(new FileInputStream(f),null,o); //Find the correct scale value. It should be the power of 2. final int REQUIRED_SIZE=300; int width_tmp=o.outWidth, height_tmp=o.outHeight; int scale=1; while(true){ if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE) break; width_tmp/=2; height_tmp/=2; scale*=2; } //decode with inSampleSize BitmapFactory.Options o2 = new BitmapFactory.Options(); o2.inSampleSize=scale; try{ return BitmapFactory.decodeStream(new FileInputStream(f), null, o2); }catch(FileNotFoundException e){ return null; } } catch (FileNotFoundException e) {} return null; } //Task for the queue private class PhotoToLoad { public String url; public ImageView imageView; public PhotoToLoad(String u, ImageView i){ url=u; imageView=i; } } 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(); } Bitmap bmp=getBitmap(photoToLoad.url); cache.put(photoToLoad.url, bmp); Object tag=photoToLoad.imageView.getTag(); if(tag!=null && ((String)tag).equals(photoToLoad.url)){ BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad.imageView); Activity a=(Activity)photoToLoad.imageView.getContext(); a.runOnUiThread(bd); } } if(Thread.interrupted()) break; } } catch (InterruptedException e) { } } } PhotosLoader photoLoaderThread=new PhotosLoader(); class BitmapDisplayer implements Runnable { Bitmap bitmap; ImageView imageView; public BitmapDisplayer(Bitmap b, ImageView i){bitmap=b;imageView=i;} public void run() { if(bitmap!=null) imageView.setImageBitmap(bitmap); else imageView.setImageResource(stub_id); BitmapDrawable drawable = (BitmapDrawable) imageView.getDrawable(); drawable.setAntiAlias(true); imageView.setScaleType(ScaleType.CENTER_INSIDE); imageView.clearAnimation(); //Log.e("Animation","Cleared"); } } public void clearCache() { cache.clear(); //clear SD cache File[] files=cacheDir.listFiles(); for(File f:files) f.delete(); } }

和getview方法如下:

public View getView(int position, View convertView, ViewGroup parent) {
        View vi=convertView;
        ViewHolder holder;
        if(convertView==null){
            vi = inflater.inflate(R.layout.videoitem, null);
            holder=new ViewHolder();
            holder.text=(TextView)vi.findViewById(R.id.text);
            holder.image=(ImageView)vi.findViewById(R.id.image);
            holder.typetext=(TextView)vi.findViewById(R.id.typetext);
            holder.description=(TextView)vi.findViewById(R.id.description);
            vi.setTag(holder);
        }else{
            holder=(ViewHolder)vi.getTag();
        }
        String dprow="";


        //data comes from search list
        if(!data.get(position).getTitle().trim().equalsIgnoreCase("")){
            dprow+="<b><strike>"+data.get(position).getTitle().trim()+"</strike></b>"+"<br>";
        }

        String urltoload="http://img.youtube.com/vi/"+data.get(position).getYoutube()+"/0.jpg";
        if(urltoload.contains(" ")){                 
            urltoload=urltoload.replace(" ", "%20");                   
        }
        holder.text.setText(Html.fromHtml(dprow));
        holder.image.setTag(urltoload);
        holder.typetext.setText(data.get(position).getType());
        holder.description.setText(urltoload);

        imageLoader.DisplayImage(urltoload, activity, holder.image);
        return vi;
    }

我使用notifyDataSetChanged()来刷新视图但它的速度很慢。是否有更好的方法可以在背景中为每个视图加载图像!

1 个答案:

答案 0 :(得分:0)

使用3个不同的图像加载器(延迟加载器的对象)来加载每个类的图像。因为懒惰列表检查旧请求和视图(如果存在)然后取消它并添加新图像的请求。