ImageLoader的仅载入列表中的图像列表项已经关闭屏幕后 [英] Imageloader only loading images in list after listitem has gone off screen

查看:194
本文介绍了ImageLoader的仅载入列表中的图像列表项已经关闭屏幕后的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有从URL中通过ImageLoader的类适配器加载图像列表视图。
是,直到列表项已滚动关闭屏幕不显示的问题在屏幕上的图像/加载。

所以基本上,列表视图显示,但直到你向下滚动,滚动再次回升没有图像加载。显示它们在第一时间内没有图像加载,直到您滚动回给他们这aplies到列表中,所有的项目。

我没有写的ImageLoader的类我和林有一个很难确切地理解为什么图像不上第一显示加载。已经尝试了很多不同的东西与队列但似乎没有任何帮助。

在ImageLoader的类:

 公共类ImageLoader的{    //最简单的内存缓存的实现。这应该与类似SoftReference的或BitmapOptions.inPurgeable更换(自1.6)
    私人的HashMap<弦乐,位图>缓存=新的HashMap<弦乐,位图>();
    私人文件cacheDir;    公共ImageLoader的(上下文的背景下){
        //使THEAD背景低优先级。这样也不会影响用户界面性能
        photoLoaderThread.setPriority(Thread.NORM_PRIORITY-1);        //查找目录保存缓存图像
        如果(android.os.Environment.getExternalStorageState()。等于(android.os.Environment.MEDIA_MOUNTED))
            cacheDir =新的文件(android.os.Environment.getExternalStorageDirectory(),LazyList);
        其他
            cacheDir = context.getCacheDir();
        如果(!cacheDir.exists())
            cacheDir.mkdirs();
    }    最终诠释stub_id = R.drawable.nopic;    公共无效DisplayImage(字符串URL,活动活动,ImageView的ImageView的,进度进度)
    {
        如果(cache.containsKey(URL)){
            imageView.setImageBitmap(cache.get(URL));
            如果(进度!= NULL){
                progressBar.setVisibility(View.GONE);
                imageView.setVisibility(View.VISIBLE);
            }
        }其他{
            queuePhoto(URL,活动,ImageView的,进度);            如果(进度!= NULL){
                imageView.setVisibility(View.GONE); //添加
                progressBar.setVisibility(View.VISIBLE);
            }其他{
                imageView.setImageResource(stub_id);
            }
        }
    }    私人无效queuePhoto(字符串URL,活动活动,ImageView的ImageView的,进度进度)
    {        //这个ImageView的可之前用于其它图像。所以有可能在队列中的一些旧的任务。我们需要将它们丢弃。
        photosQueue.Clean(ImageView的);
        PhotoToLoad P =新PhotoToLoad(URL,ImageView的,进度);
        同步(photosQueue.photosToLoad){
            photosQueue.photosToLoad.push(P);
            photosQueue.photosToLoad.notifyAll();
        }        //启动线程,如果它尚未启动
        如果(photoLoaderThread.getState()== Thread.State.NEW)
            photoLoaderThread.start();
    }    私人位图getBitmap(字符串URL)
    {
        //我通过哈希code识别图像。没有一个完美的解决方案,很好的演示。
        字符串文件名=将String.valueOf(url.hash code());
        文件f =新的文件(cacheDir,文件名);        //从SD缓存
        位图B =去codeFILE(F);
        如果(B!= NULL)
            返回b;        //从网页
        尝试{
            位图位图= NULL;
            InputStream的是=新的URL(网址).openStream();
            OutputStream的OS =新的FileOutputStream(F);
            Utils.CopyStream(是,OS);
            os.close();
            位=去codeFILE(F);
            返回位图;
        }赶上(例外前){
            ex.printStackTrace();
            返回null;
        }
    }    //德$ C $连拍影像的鳞它来减少内存消耗
    私人位图德codeFILE(文件f){
        尝试{
            //德code图像尺寸
            BitmapFactory.Options O =新BitmapFactory.Options();
            o.inJustDe codeBounds = TRUE;
            BitmapFactory.de codeStream(新的FileInputStream(F),空,O);            //找到正确的比例值。它应该是2的幂。
            INT requiredSize = 100;            INT width_tmp = o.outWidth,height_tmp = o.outHeight;
            int标= 1;
            而(真){
                如果(width_tmp / 2'; requiredSize || height_tmp / 2版; requiredSize)
                    打破;
                width_tmp / = 2;
                height_tmp / = 2;
                规模* = 2;
            }            //德code。与inSampleSize
            BitmapFactory.Options O2 =新BitmapFactory.Options();
            o2.inSampleSize =规模;
            返回BitmapFactory.de codeStream(新的FileInputStream(F),空,O2);
        }赶上(FileNotFoundException异常五){}
        返回null;
    }    //任务队列
    私有类PhotoToLoad
    {
        公共字符串的URL;
        公共ImageView的ImageView的;
        公众进度进度;
        公共PhotoToLoad(字符串U,ImageView的我,进度P){
            URL = U;
            ImageView的= I;
            进度= P;
        }
    }    PhotosQueue photosQueue =新PhotosQueue();    公共无效stopThread(){
        photoLoaderThread.interrupt();
    }    //照片商店列表下载
    类PhotosQueue
    {
        私人堆叠式和LT; PhotoToLoad> photosToLoad =新的堆栈< PhotoToLoad>();        //删除此的ImageView的所有实例
        公共无效清洁(ImageView的图片)
        {
            为(中间体J = 0; J&下; photosToLoad.size()){
                如果(photosToLoad.get(J).imageView ==图片)
                    photosToLoad.remove(J);
                其他
                    ++焦耳;
            }
        }
    }    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    // PHOTOSLOADER:螺纹
    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX    类PhotosLoader继承Thread {
        公共无效的run(){
            尝试{
                而(真)
                {
                    //线程等待直到有任何图像队列中的加载
                    如果(photosQueue.photosToLoad.size()== 0)
                        同步(photosQueue.photosToLoad){
                            photosQueue.photosToLoad.wait();
                        }
                    如果(photosQueue.photosToLoad.size()!= 0)
                    {
                        PhotoToLoad photoToLoad;
                        同步(photosQueue.photosToLoad){
                                                            photoToLoad = photosQueue.photosToLoad.pop(); photosQueue.photosToLoad.remove(photoToLoad);
                        }
                        BMP位图= getBitmap(photoToLoad.url);
                        cache.put(photoToLoad.url,BMP);
                        对象标记= photoToLoad.imageView.getTag();
                        如果(标记= NULL&放大器;!及((字符串)标签).equals(photoToLoad.url)){
                            BitmapDisplayer BD =新BitmapDisplayer(BMP,photoToLoad.imageView,photoToLoad.progressBar);
                            活动一=(活动)photoToLoad.imageView.getContext();
                            a.runOnUiThread(BD);
                        }
                    }
                    如果(Thread.interrupted())
                        打破;
                }
            }赶上(InterruptedException的E){
                //允许线程退出
            }
        }
    }    PhotosLoader photoLoaderThread =新PhotosLoader();
    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    //位图显示器
    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX    //用在UI线程来显示位图
    类BitmapDisplayer实现Runnable {
        位图位图;
        ImageView的ImageView的;
        进度进度;
        公共BitmapDisplayer(位图B,ImageView的我,进度P){
            位= B;
            ImageView的= I;
            进度= P;
        }
        公共无效的run(){
            如果(位图!= NULL){
                imageView.setImageBitmap(位图);
                如果(进度!= NULL){
                    imageView.setVisibility(View.VISIBLE);
                    progressBar.setVisibility(View.GONE);
                }
            }其他{
                如果(进度!= NULL){
                    progressBar.setVisibility(View.VISIBLE);
                    imageView.setVisibility(View.GONE);
                }
            }
        }
    }    公共无效clearCache(){
        //清除内存高速缓存
        cache.clear();        //清SD缓存
        文件[] =文件cacheDir.listFiles();
        对于(F文件:文件)
            f.delete();
    }
}

该适配器:

 公共类Adapter_Agenda延伸BaseAdapter {    // DEBUG
    私人最终字符串标记= this.getClass()getSimpleName()。    私人LayoutInflater吹气= NULL;
    公共ViewHolder持有人;
    私人的ArrayList<议程与GT;议程;
    UnixTimeToStringConverter unixConverter;
ImageLoader的ImageLoader的;    查看六;    公共Adapter_Agenda(上下文的背景下,ArrayList的<议程与GT;议程){        this.agendas =议程;
        unixConverter =新UnixTimeToStringConverter();
         ImageLoader的=新ImageLoader的(上下文);
        吹气=(LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }    公众诠释的getCount(){
        返回agendas.size();
    }    @覆盖
    公共议程的getItem(INT位置){
        返回agendas.get(位置);
    }    众长getItemId(INT位置){
        返回的位置;
    }    公共查看getView(INT位置,查看convertView,父母的ViewGroup){        VI = convertView;        如果(convertView == NULL){            VI = inflater.inflate(R.layout.item_list_agenda,NULL);
            持有人=新ViewHolder();            holder.header =(TextView中)vi.findViewById(R.id.item_list_header);
                    holder.image =(ImageView的)vi.findViewById(R.id.item_list_image);
            holder.time =(TextView中)vi.findViewById(R.id.item_list_time);
            holder.description =(TextView中)vi.findViewById(R.id.item_list_description);            vi.setTag(保持器);
            支架=(ViewHolder)vi.getTag();
        }其他{
            支架=(ViewHolder)vi.getTag();
        }        holder.header.setText(agendas.get(位置).getHeader());
        imageLoader.DisplayImage(agendas.get(位置).getImageURL(),活动,holder.image,NULL);
   holder.time.setText(unixConverter.getUnixDateFormated(agendas.get(位置).getStartTime()));        返回VI;
    }    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    // VIEWHOLDER
    // XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    公共类ViewHolder {        公共TextView的时间;
            公众形象ImageView的;
        公众的TextView头;
        公共TextView的描述;    }
}


解决方案

只是把

  holder.image.setTag(agendas.get(位置).getImageURL());

  imageLoader.DisplayImage(agendas.get(位置).getImageURL(),活动,holder.image,NULL);

I have a listView with an adapter loading images from URLs through a ImageLoader class. The problem is, the images on the screen are not displayed/loaded until the list item has been scrolled off screen.

So basically, the listView is shown, but no images are loaded until you scroll down and scroll back up again. This aplies to all the items in the list, when displaying them the first time no images are loaded until you scroll back to them.

I have not written the ImageLoader class myself and Im having a hard time understanding exactly why the images don't load on the first displaying. Have tried alot of different things with the queue but nothing seems to help.

The ImageLoader class:

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, Bitmap> cache=new HashMap<String, Bitmap>();
    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(),"LazyList");
        else
            cacheDir=context.getCacheDir();
        if(!cacheDir.exists())
            cacheDir.mkdirs();
    }

    final int stub_id=R.drawable.nopic;

    public void DisplayImage(String url, Activity activity, ImageView imageView, ProgressBar progressBar)
    {
        if(cache.containsKey(url)){
            imageView.setImageBitmap(cache.get(url));
            if (progressBar != null){
                progressBar.setVisibility(View.GONE);
                imageView.setVisibility(View.VISIBLE);
            }
        }else{
            queuePhoto(url, activity, imageView, progressBar);

            if(progressBar != null){
                imageView.setVisibility(View.GONE); //ADDED
                progressBar.setVisibility(View.VISIBLE);
            } else {
                imageView.setImageResource(stub_id);
            }
        }    
    }

    private void queuePhoto(String url, Activity activity, ImageView imageView, ProgressBar progressBar)
    {

        //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, progressBar);
        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 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);
            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.
            int requiredSize = 100;

            int width_tmp=o.outWidth, height_tmp=o.outHeight;
            int scale=1;
            while(true){
                if(width_tmp/2<requiredSize || height_tmp/2<requiredSize)
                    break;
                width_tmp/=2;
                height_tmp/=2;
                scale*=2;
            }

            //decode with inSampleSize
            BitmapFactory.Options o2 = new BitmapFactory.Options();
            o2.inSampleSize=scale;
            return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
        } catch (FileNotFoundException e) {}
        return null;
    }

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

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

    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    // PHOTOSLOADER: Thread
    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    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();                                                       photosQueue.photosToLoad.remove(photoToLoad);
                        }
                        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, photoToLoad.progressBar);
                            Activity a = (Activity)photoToLoad.imageView.getContext();
                            a.runOnUiThread(bd);
                        }
                    }
                    if(Thread.interrupted())
                        break;
                }
            } catch (InterruptedException e) {
                //allow thread to exit
            }
        }
    }

    PhotosLoader photoLoaderThread = new PhotosLoader();


    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    // BITMAP DISPLAYER
    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

    //Used to display bitmap in the UI thread
    class BitmapDisplayer implements Runnable{
        Bitmap      bitmap;
        ImageView   imageView;
        ProgressBar progressBar;
        public BitmapDisplayer(Bitmap b, ImageView i, ProgressBar p){
            bitmap = b; 
            imageView = i; 
            progressBar = p;
        }
        public void run(){
            if(bitmap != null){
                imageView.setImageBitmap(bitmap);
                if (progressBar != null){
                    imageView.setVisibility(View.VISIBLE);
                    progressBar.setVisibility(View.GONE);
                }
            }else{
                if (progressBar != null){
                    progressBar.setVisibility(View.VISIBLE);
                    imageView.setVisibility(View.GONE);
                }
            }
        }
    }

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

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

The Adapter:

public class Adapter_Agenda extends BaseAdapter {

    // DEBUG
    private final String TAG = this.getClass().getSimpleName();

    private LayoutInflater inflater = null;
    public ViewHolder holder;
    private ArrayList<Agenda> agendas;
    UnixTimeToStringConverter unixConverter;
ImageLoader imageLoader;

    View vi;

    public Adapter_Agenda(Context context, ArrayList<Agenda> agendas) {

        this.agendas = agendas;
        unixConverter = new UnixTimeToStringConverter();
         imageLoader = new ImageLoader(context);
        inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public int getCount() {
        return agendas.size();
    }

    @Override
    public Agenda getItem(int position) {
        return agendas.get(position);
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {

        vi = convertView;

        if(convertView  ==  null){

            vi = inflater.inflate(R.layout.item_list_agenda, null);
            holder = new ViewHolder();

            holder.header       = (TextView)vi.findViewById(R.id.item_list_header);
                    holder.image            = (ImageView)vi.findViewById(R.id.item_list_image);
            holder.time         = (TextView)vi.findViewById(R.id.item_list_time);
            holder.description  = (TextView)vi.findViewById(R.id.item_list_description);

            vi.setTag(holder);
            holder = (ViewHolder)vi.getTag();
        } else {
            holder = (ViewHolder)vi.getTag();
        }

        holder.header.setText(agendas.get(position).getHeader());
        imageLoader.DisplayImage(agendas.get(position).getImageURL(), activity, holder.image, null);
   holder.time.setText(unixConverter.getUnixDateFormated(agendas.get(position).getStartTime()));

        return vi;
    }

    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    // VIEWHOLDER
    //XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    public class ViewHolder{

        public TextView         time;
            public ImageView                image;
        public TextView         header;
        public TextView         description;

    }
}

解决方案

just put

holder.image.setTag(agendas.get(position).getImageURL());

before

imageLoader.DisplayImage(agendas.get(position).getImageURL(), activity, holder.image, null);

这篇关于ImageLoader的仅载入列表中的图像列表项已经关闭屏幕后的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆