使用AsyncTask的加载ListView中图片 [英] Using AsyncTask to load Images in ListView

查看:201
本文介绍了使用AsyncTask的加载ListView中图片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个ListView控件可容纳的图像。这取决于如果图像存在与否的SD卡。

下面我举的例子code:

 公共类MainActivity延伸活动{

    ListView控件mListView;

    @覆盖
    保护无效的onCreate(包savedInstanceState){
        super.onCreate(savedInstanceState);

        mListView =新的ListView(本);
        的setContentView(mListView);

        的String [] ARR =新的String [] {
                /example/images/1.jpg,/example/images/2.jpg,
                /example/images/3.jpg,/example/images/4.jpg,
                /example/images/5.jpg,/example/images/6.jpg,
                /example/images/7.jpg,/example/images/8.jpg,
                /example/images/9.jpg,/example/images/1.jpg,
                /example/images/2.jpg,/example/images/3.jpg,
                /example/images/4.jpg,/example/images/5.jpg,
                /example/images/6.jpg,/example/images/7.jpg,
                /example/images/8.jpg,/example/images/9.jpg,
                /example/images/1.jpg,/example/images/2.jpg,
                /example/images/3.jpg,/example/images/4.jpg,
                /example/images/5.jpg,/example/images/6.jpg,
                /example/images/7.jpg,/example/images/8.jpg,
                /example/images/9.jpg,/example/images/1.jpg,
                /example/images/2.jpg,/example/images/3.jpg,
                /example/images/4.jpg,/example/images/5.jpg,
                /example/images/6.jpg,/example/images/7.jpg,
                /example/images/8.jpg,/example/images/9.jpg};

        名单<字符串>表= Arrays.asList(ARR);

        MyAdapter适配器=新MyAdapter(这一点,R.layout.listitem_imv,清单);

        mListView.setAdapter(适配器);
    }

    类MyAdapter扩展ArrayAdapter<字符串> {

        名单<字符串> mList;
        LayoutInflater mInflater;
        INT mResource;

        公共MyAdapter(上下文的背景下,INT资源,
                名单<字符串>对象){
            超(背景下,资源对象);

            mResource =资源;
            mInflater = getLayoutInflater();
            mList =物体;
        }

        @覆盖
        公共查看getView(INT位置,查看convertView,ViewGroup中父){
            查看图。

            如果(convertView == NULL){
                鉴于= mInflater.inflate(mResource,NULL);
            }其他{
                鉴于= convertView;
            }

            ImageView的ImageView的=(ImageView的)view.findViewById(R.id.imv);
            TextView中的TextView =(TextView中)view.findViewById(R.id.txv);

                            imageView.setTag(mList.get(位置)); // ImageView的的标签==路径图像
            新的LoadImage()执行(ImageView的);
            textView.setText(mList.get(位置)的ToString());

            返回查看;
        }
    }

    一流的LoadImage扩展的AsyncTask<对象,太虚,位图> {

        私人ImageView的IMV;
        私人字符串路径;


        @覆盖
        受保护的位图doInBackground(对象... PARAMS){
            IMV =(ImageView的)PARAMS [0];

            。PATH = imv.getTag()的toString();

            点阵位图= NULL;
            档案文件=新的文件(
                    。Environment.getExternalStorageDirectory()getAbsolutePath()+路径);

            如果(file.exists()){
                位= BitmapFactory.de codeFILE(file.getAbsolutePath());
            }

            返回的位图;
        }
        @覆盖
        保护无效onPostExecute(位图的结果){
            如果(结果= NULL和放大器;!&安培; IMV!= NULL){
                imv.setVisibility(View.VISIBLE);
                imv.setImageBitmap(结果);
            }其他{
                imv.setVisibility(View.GONE);
            }
        }
    }
}
 

在'SD卡/例子/图片目录中有图片:1.JPG,2.JPG,3.JPG,4.JPG,6.JPG,7.JPG和9.jpg。 预期的结果是:

但是,如果我快速滚动列表,有些图片插入错误的项目。 它发生由于使用convertView的getView()方法。

如果我用下面的code时,code正常工作:

  //如果(convertView == NULL){
        //视图= mInflater.inflate(mResource,NULL);
        //}其他{
        //视图= convertView;
        //}
        鉴于= mInflater.inflate(mResource,NULL);
 

在列表滚动快,二asyncTasks可引用一个相同的观点,由于使用convertView的。 我怎样才能取消的​​AsyncTask当查看不再可见?(是useb通过ListView控件的其他项目)

修改

  @覆盖
    保护无效onPostExecute(位图的结果){
        如果(结果= NULL和放大器;!&安培; IMV!= NULL){

            如果(imv.getTag()。等于(路径)){
                imv.setVisibility(View.VISIBLE);
                imv.setImageBitmap(结果);
            }其他{
                imv.setVisibility(View.GONE);
            }

        }其他{
            imv.setVisibility(View.GONE);
        }
    }
 

解决方案

您可以发送ImageView的的任务构造并保持一个参考图片路径那里。现在,在onPostExecute,检查ImageView的当前标签是一样的,你开始与一个。如果是,则设置图像。如果没有,什么也不做。

然而,这意味着图像将在任何情况下被下载。你只是没有设置错误的图像上的看法。

编辑: 首先ImageView的传递给任务构造器:

 新的LoadImage(ImageView的).execute()
 

然后保存一个参考的LoadImage构造函数中的ImageView和映像路径。重要的是要保存路径在构造函数中,而不是在doInBackground,以确保我们不会遇到多线程问题是很重要的。然后,在onPostExecute我们检查当前路径。

 类的LoadImage扩展的AsyncTask<对象,太虚,位图> {

        私人ImageView的IMV;
        私人字符串路径;

        公众的LoadImage(ImageView的IMV){
             this.imv = IMV;
             this.path = imv.getTag()的toString()。
        }

    @覆盖
    受保护的位图doInBackground(对象... PARAMS){
        点阵位图= NULL;
        档案文件=新的文件(
                。Environment.getExternalStorageDirectory()getAbsolutePath()+路径);

        如果(file.exists()){
            位= BitmapFactory.de codeFILE(file.getAbsolutePath());
        }

        返回的位图;
    }
    @覆盖
    保护无效onPostExecute(位图的结果){
        如果(!imv.getTag()的toString()。等于(路径)){
               / *的路径不是一样的。这意味着该
                  图像视图是由其他一些异步任务处理。
                  我们没有做任何事情,回报。 * /
               返回;
        }

        如果(结果= NULL和放大器;!&安培; IMV!= NULL){
            imv.setVisibility(View.VISIBLE);
            imv.setImageBitmap(结果);
        }其他{
            imv.setVisibility(View.GONE);
        }
    }

}
 

I have one ListView which can hold an image. It depends if image exists or not in SDCARD.

Here my example code:

public class MainActivity extends Activity  {

    ListView mListView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        mListView = new ListView(this);
        setContentView(mListView);

        String[] arr = new String[] { 
                "/example/images/1.jpg", "/example/images/2.jpg",  
                "/example/images/3.jpg", "/example/images/4.jpg",  
                "/example/images/5.jpg", "/example/images/6.jpg", 
                "/example/images/7.jpg", "/example/images/8.jpg",  
                "/example/images/9.jpg", "/example/images/1.jpg", 
                "/example/images/2.jpg", "/example/images/3.jpg",  
                "/example/images/4.jpg", "/example/images/5.jpg",  
                "/example/images/6.jpg", "/example/images/7.jpg",  
                "/example/images/8.jpg", "/example/images/9.jpg", 
                "/example/images/1.jpg", "/example/images/2.jpg",  
                "/example/images/3.jpg", "/example/images/4.jpg",  
                "/example/images/5.jpg", "/example/images/6.jpg", 
                "/example/images/7.jpg", "/example/images/8.jpg",  
                "/example/images/9.jpg", "/example/images/1.jpg", 
                "/example/images/2.jpg", "/example/images/3.jpg",  
                "/example/images/4.jpg", "/example/images/5.jpg",  
                "/example/images/6.jpg", "/example/images/7.jpg",  
                "/example/images/8.jpg", "/example/images/9.jpg"}; 

        List<String> list = Arrays.asList(arr);

        MyAdapter adapter = new MyAdapter(this, R.layout.listitem_imv, list);

        mListView.setAdapter(adapter);
    }

    class MyAdapter extends ArrayAdapter<String>{

        List<String> mList;
        LayoutInflater mInflater;
        int mResource;

        public MyAdapter(Context context, int resource,
                List<String> objects) {
            super(context, resource, objects);

            mResource = resource;
            mInflater = getLayoutInflater();
            mList = objects;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View view;

            if(convertView == null){
                view = mInflater.inflate(mResource, null);
            }else{
                view = convertView;
            }

            ImageView imageView = (ImageView) view.findViewById(R.id.imv);
            TextView textView = (TextView) view.findViewById(R.id.txv);

                            imageView.setTag(mList.get(position));//tag of imageView == path to image
            new LoadImage().execute(imageView);
            textView.setText(mList.get(position).toString());

            return view;
        }       
    }

    class LoadImage extends AsyncTask<Object, Void, Bitmap>{

        private ImageView imv;
        private String path;


        @Override
        protected Bitmap doInBackground(Object... params) {
            imv = (ImageView)   params[0];

            path = imv.getTag().toString();

            Bitmap bitmap = null;
            File file = new File( 
                    Environment.getExternalStorageDirectory().getAbsolutePath() + path);

            if(file.exists()){
                bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
            }

            return bitmap;
        }
        @Override
        protected void onPostExecute(Bitmap result) {
            if(result != null && imv != null){
                imv.setVisibility(View.VISIBLE);
                imv.setImageBitmap(result);
            }else{
                imv.setVisibility(View.GONE);
            }
        }
    }
}

The 'sdcard/example/images' directory has the images: 1.jpg, 2.jpg, 3.jpg, 4.jpg, 6.jpg, 7.jpg and 9.jpg. the expected result is:

But, if I scroll the list quickly, some images are inserted in the wrong items. It happens due to use of convertView in getView() method.

If I use the following code, the code works fine:

        //if(convertView == null){
        //  view = mInflater.inflate(mResource, null);
        //}else{
        //  view = convertView;
        //}
        view = mInflater.inflate(mResource, null);

When list scrolled quickly, two asyncTasks can reference one same View, due to use of convertView. How Can I cancel AsyncTask when the View is no longer visible?(and is useb by another item of ListView)

edit

            @Override
    protected void onPostExecute(Bitmap result) {
        if(result != null && imv != null){

            if(imv.getTag().equals(path)){
                imv.setVisibility(View.VISIBLE);
                imv.setImageBitmap(result);
            }else{
                imv.setVisibility(View.GONE);
            }

        }else{
            imv.setVisibility(View.GONE);
        }
    }

解决方案

You can send in the ImageView to the task constructor and keep a reference to the image path there. Now at onPostExecute, check if the current tag of the ImageView is the same as the one that you started with. If yes, then set the image. If no, don't do anything.

However, this means that the image will be downloaded in any case. You'll just not set the wrong image on the view.

EDIT: First pass the ImageView to the task constructor:

new LoadImage(imageView).execute()

Then save a reference to the ImageView and image path in LoadImage constructor. It is important to save the path in the constructor and not in doInBackground to ensure that we don't run into multi threading problems. Then at onPostExecute we check the current path.

class LoadImage extends AsyncTask<Object, Void, Bitmap>{

        private ImageView imv;
        private String path;

        public LoadImage(ImageView imv) {
             this.imv = imv;
             this.path = imv.getTag().toString();
        }

    @Override
    protected Bitmap doInBackground(Object... params) {
        Bitmap bitmap = null;
        File file = new File( 
                Environment.getExternalStorageDirectory().getAbsolutePath() + path);

        if(file.exists()){
            bitmap = BitmapFactory.decodeFile(file.getAbsolutePath());
        }

        return bitmap;
    }
    @Override
    protected void onPostExecute(Bitmap result) {
        if (!imv.getTag().toString().equals(path)) {
               /* The path is not same. This means that this
                  image view is handled by some other async task. 
                  We don't do anything and return. */
               return;
        }

        if(result != null && imv != null){
            imv.setVisibility(View.VISIBLE);
            imv.setImageBitmap(result);
        }else{
            imv.setVisibility(View.GONE);
        }
    }

}

这篇关于使用AsyncTask的加载ListView中图片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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