android-ListAdapter任务不可能吗?将ImageViews和Animations结合在一起吗?

android-ListAdapter任务不可能吗?将ImageViews和Animations结合在一起吗?,第1张

概述我有一个列表适配器,其中图像加载有旋转进度动画,直到从网上获取它们为止.当我在listView中向下滚动时,似乎动画旋转了上一张图像…这是一个非常奇怪且令人讨厌的效果.唯一应该旋转的是进度动画.我使用一个称为ImageLoader的类来异步netfetch图像:finalintstub_id=R.drawable.p

我有一个列表适配器,其中图像加载有旋转进度动画,直到从网上获取它们为止.当我在ListVIEw中向下滚动时,似乎动画旋转了上一张图像…这是一个非常奇怪且令人讨厌的效果.唯一应该旋转的是进度动画.

我使用一个称为ImageLoader的类来异步netfetch图像:

final int stub_ID=R.drawable.progress;public voID displayImage(String url, Activity activity, ImageVIEw imageVIEw,int size){    //Log.d("ImageLoader" , url);    this.size=size;    if(cache.containsKey(url)) {        //If this works, then why do the olD images still spin??                    imageVIEw.clearanimation();        //imageVIEw.setBackgroundDrawable(null);        //imageVIEw.setimageDrawable(null);        imageVIEw.setimageBitmap(cache.get(url));    }    else    {        rotation = AnimationUtils.loadAnimation(activity, R.drawable.progress);        rotation.setRepeatCount(Animation.INFINITE);        imageVIEw.startAnimation(rotation);        queuePhoto(url, activity, imageVIEw);        //imageVIEw.setimageResource(stub_ID);        //imageVIEw.setBackgroundResource(stub_ID);     }    Resources r = activity.getResources();    int dip = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, r.getdisplayMetrics());    LayoutParams layoutParams = imageVIEw.getLayoutParams();    layoutParams.height = dip;    layoutParams.wIDth = dip;    imageVIEw.setLayoutParams(layoutParams);}

现在您可能会问,queuePhoto是做什么的?这是动画开始的唯一其他地方.

//Used to display bitmap in the UI threadclass Bitmapdisplayer implements Runnable{    Bitmap bitmap;    ImageVIEw imageVIEw;    public Bitmapdisplayer(Bitmap b, ImageVIEw i){bitmap=b;imageVIEw=i;}    public voID run()    {        if(bitmap!=null) {            imageVIEw.clearanimation();            imageVIEw.setimageBitmap(bitmap);        }        else {            imageVIEw.clearanimation();            rotation = AnimationUtils.loadAnimation(context, R.drawable.progress);            rotation.setRepeatCount(Animation.INFINITE);            imageVIEw.startAnimation(rotation);            //imageVIEw.setimageResource(stub_ID);        }    }}

现在,我的列表适配器的getVIEw的一部分:

    @OverrIDe    public VIEw getVIEw(int position, VIEw convertVIEw, VIEwGroup parent) {        if( convertVIEw == null ){            vi = inflater.inflate(R.layout.trending_item, null);            holder=new VIEwHolder();            holder.img1 = (ImageVIEw) vi.findVIEwByID(R.ID.t_item_1);            holder.img2 = (ImageVIEw) vi.findVIEwByID(R.ID.t_item_2);            holder.img3 = (ImageVIEw) vi.findVIEwByID(R.ID.t_item_3);            vi.setTag(holder);        } else {            holder=(VIEwHolder)vi.getTag();        }        JsONObject t1= ts.get(1);        if(t1 !=null) {                holder.img1.setTag(t1.getString("image_small"));                imageLoader.displayImage(t1.getString("image_small"), act, holder.img1,IMAGE_SIZE);                holder.img1.setTag(TAG_T t1.getString("ID"));                holder.img1.setonClickListener(ocl);            } else {                holder.img1.setimageDrawable(null);                holder.img1.setBackgroundDrawable(null);                    holder.img1.setTag(null);                   holder.img1.setTag(TAG_T, null);            }

更新

我实现了JBM提出的解决方案,但是我无法使其工作,他建议在UI线程上运行.

public class RemoteImageVIEw extends ImageVIEw implements RemoteLoadListener {final int stub_ID=R.drawable.progress;int size;private HashMap<String, Bitmap> cache=new HashMap<String, Bitmap>();Animation rotation;private file cacheDir;public RemoteImageVIEw(Context context, AttributeSet attrs, int defStyle) {    super(context, attrs, defStyle);}public RemoteImageVIEw(Context context, AttributeSet attrs) {    super(context, attrs);    //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(),context.getString(R.string.app_name));    else        cacheDir=context.getCacheDir();    if(!cacheDir.exists())        cacheDir.mkdirs();}public RemoteImageVIEw(Context context) {    super(context);}public voID displayRemoteImage(String url, Activity activity, int size){    this.myUrl = url;    this.size=size;    Resources r = activity.getResources();    int dip = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, r.getdisplayMetrics());    LayoutParams layoutParams = this.getLayoutParams();    layoutParams.height = dip;    layoutParams.wIDth = dip;    this.setLayoutParams(layoutParams);    if(cache.containsKey(url)) {        this.clearanimation();        setimageBitmap(cache.get(url));    }    else    {        rotation = AnimationUtils.loadAnimation(activity, R.drawable.progress);        rotation.setRepeatCount(Animation.INFINITE);        this.startAnimation(rotation);        queuePhoto(url, activity, this);    }}@OverrIDepublic voID onl oadSuccess(String url, Bitmap bmp) {    if (url.equals(myUrl)) {        setimageBitmap(bmp);    } else {        /* the arrived bitmap is stale. do nothing. */    }}@OverrIDepublic voID onl oadFail(String url) {    if (url.equals(myUrl)) {        setimageBitmap(((BitmapDrawable)getResources().getDrawable(stub_ID)).getBitmap());    } else {        /* the Failed bitmap is stale. do nothing. */    }}String myUrl;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();}PhotosQueue photosQueue=new PhotosQueue();public voID stopThread(){    photoloaderThread.interrupt();}//stores List of photos to downloadclass 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;        }    }}//Task for the queueprivate class PhotoToload{    public String url;    public ImageVIEw imageVIEw;    public PhotoToload(String u, ImageVIEw i){        url=u;         imageVIEw=i;    }}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) {            //allow thread to exit        }    }}Photosloader photoloaderThread=new Photosloader();//Used to display bitmap in the UI threadclass Bitmapdisplayer implements Runnable{    Bitmap bitmap;    ImageVIEw imageVIEw;    public Bitmapdisplayer(Bitmap b, ImageVIEw i){bitmap=b;imageVIEw=i;}    public voID run()    {           if(bitmap!=null) {            imageVIEw.clearanimation();            imageVIEw.setimageBitmap(bitmap);        }        else {            imageVIEw.clearanimation();            imageVIEw.setimageResource(stub_ID);        }    }}private Bitmap getBitmap(String url) {    System.out.println("GET: " +url);    if(url== null) {        return null;    }    //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 consumptionprivate 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 wIDth_tmp=o.outWIDth, height_tmp=o.outHeight;        int scale=1;        while(true){            if(wIDth_tmp/2<size || height_tmp/2<size)                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) {        Log.d("ImageLoader",e.getMessage(),e);    }    return null;}

}

解决方法:

这里的问题是ImageVIEw与displayImage函数之间的竞争.当列表向上或向下滚动时,行将被重用,因此,当远程映像到达时,通常会发生其目标视图已经属于另一行的情况.唯一可靠的方法是让您拥有自己的类RemoteImageVIEw来扩展ImageVIEw,该ImageVIEw可在内部处理图像.然后,RemoteImageVIEw可以进行适当的同步.

让您的queuePhoto方法采用RemoteLoadListener代替ImageVIEw,如下所示:

public interface RemoteLoadListener {    voID onl oadFail(String url);    voID onl oadSuccess(String url, Bitmap bmp);}

然后将RemoteImageVIEw设置为RemoteLoadListener并在内部执行所有 *** 作:

public class RemoteImageVIEw extends ImageVIEw implements RemoteLoadListener {    final int static stub_ID=R.drawable.progress;    public voID displayImage(String url, Activity activity, int size)    {        myUrl = url;        if(cache.containsKey(url)) {            ...            setimageBitmap(cache.get(url));        }        else        {            ...            imageVIEw.startAnimation(rotation);            queuePhoto(url, activity, this);        }    }    @OverrIDe    public voID onl oadSuccess(String url, Bitmap bmp) {        if (url.equals(myUrl)) {            setimageBitmap(bmp);        } else {            /* the arrived bitmap is stale. do nothing. */        }    }    @OverrIDe    public voID onl oadFail(String url) {        if (url.equals(myUrl)) {            setimageBitmap(placeholder);        } else {            /* the Failed bitmap is stale. do nothing. */        }    }}

因此,在您的getVIEw方法中,您只需执行以下 *** 作:

holder.img1.displayImage(t1.getString("image_small"), act, IMAGE_SIZE);

更新

首先尝试降低系统的复杂性.我已经删除了您的照片队列和缓存,并将其替换为从Web上下载图像(此部分基于您的代码).我没有运行这段代码,只是输入了它.但这应该给您一个清晰的想法.

public class RemoteImageVIEw extends ImageVIEw implements RemoteLoadListener {    public RemoteImageVIEw(Context context, AttributeSet attrs) {        super(context, attrs);    }    public RemoteImageVIEw(Context context) {        super(context);    }    public voID displayRemoteImage(String url, Activity activity, int size)    {        this.myUrl = url;        this.size=size;        Resources r = activity.getResources();        int dip = (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, r.getdisplayMetrics());        LayoutParams layoutParams = this.getLayoutParams();        layoutParams.height = dip;        layoutParams.wIDth = dip;        this.setLayoutParams(layoutParams);        {            rotation = AnimationUtils.loadAnimation(activity, R.drawable.progress);            rotation.setRepeatCount(Animation.INFINITE);            this.startAnimation(rotation);            queuePhoto(url, activity, this);        }    }    @OverrIDe    public voID onl oadSuccess(String url, Bitmap bmp) {        if (url.equals(myUrl)) {            setimageBitmap(bmp);        } else {            /* the arrived bitmap is stale. do nothing. */        }    }    @OverrIDe    public voID onl oadFail(String url) {        if (url.equals(myUrl)) {            setimageBitmap(((BitmapDrawable)getResources().getDrawable(stub_ID)).getBitmap());        } else {            /* the Failed bitmap is stale. do nothing. */        }    }    String myUrl;    private voID queuePhoto(final String url, final RemoteLoadListener Listener)    {        new AsyncTask<VoID, VoID, Bitmap>() {            @OverrIDe            protected Bitmap doInBackground(VoID... params) {                //from web                Bitmap bitmap = null;                inputStream is = null;                OutputStream os = null;                try {                    is = new URL(url).openStream();                    os = new fileOutputStream(f);                    Utils.copyStream(is, os);                    bitmap = decodefile(f);                } catch (Exception ex){                    bitmap = null;                } finally {                    if (is != null) try { is.close(); } catch (IOException e) { /* ignore */ };                    if (os != null) try { os.close(); } catch (IOException e) { /* ignore */ };                }                return bitmap;            }            @OverrIDe            protected voID onPostExecute(Bitmap result) {                if (result != null) {                    Listener.onLoadSuccess(url, result);                } else {                    Listener.onLoadFail(url);                }            };        }.execute();    }}

PS:请注意尝试-在使用流时最终阻塞.

总结

以上是内存溢出为你收集整理的android-ListAdapter任务不可能吗?将ImageViews和Animations结合在一起吗?全部内容,希望文章能够帮你解决android-ListAdapter任务不可能吗?将ImageViews和Animations结合在一起吗?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1070756.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-26
下一篇 2022-05-26

发表评论

登录后才能评论

评论列表(0条)

保存