ListView BaseAdapter 挂起

ListView BaseAdapter is hanging

我的可滚动列表视图出现一些奇怪的行为。它由 BaseAdapter 控制。

当我向上或向下滚动时,它有时会挂起然后朝相反的方向弹回。我不知道为什么,也不知道如何解决它。

我的基本适配器在下面,它加载了大约 90 个带有图像和一堆文本的片段。

public class PosterListAdapter extends BaseAdapter {

        private final ArrayList<Poster> listItems;

        private final LayoutInflater inflater;

        public PosterListAdapter(ArrayList<Poster> listItems, LayoutInflater inflater) {
            this.listItems = listItems;
            this.categoryList = categoryItems;
            this.inflater = inflater;
        }       


        @Override
        public int getCount() {
            //Log.d("getCount", String.valueOf(this.listItems.size()));
            return this.listItems.size();               
        }

        @Override
        public Poster getItem(int i) {

            return this.listItems.get(i);
        }

        @Override
        public long getItemId(int i) {
            return 0;
        }

        @Override
        public View getView(int i, View convertView, ViewGroup viewGroup) {
            MyViewHolder mViewHolder;
            SparseArray<String> categoryMap = db.getCategoryMap();

            if (convertView == null) {
                convertView = inflater.inflate(R.layout.catalog_list_fragment, viewGroup, false);
                mViewHolder = new MyViewHolder(convertView);
                convertView.setTag(mViewHolder);
            } else {
                mViewHolder = (MyViewHolder) convertView.getTag();
            }

            //LayoutParams params = (LayoutParams) imageView.getLayoutParams();

            Poster item = this.listItems.get(i);

            String filename = item.getPosterFilename();

            mViewHolder.posterAuthor.setText("Author: "+item.getPresenterFname()+' '+item.getPresenterLname());
            mViewHolder.posterAltAuthors.setText("Supporting Authors: "+item.getPosterAuthors());
            mViewHolder.posterTitle.setText(item.getPosterTitle());
            mViewHolder.posterSynopsis.setText(item.getPosterSynopsis());
            mViewHolder.posterNumber.setText("Poster: "+String.valueOf(item.getPosterNumber()));
            mViewHolder.posterPresentation.setText("Live Presentation: "+item.getSessionDate()+" at "+item.getSessionTime()+"\nAt Station: "+item.getPosterStation());          

            String category = categoryMap.get(item.getCatID());

            mViewHolder.posterCategory.setText("Category: "+category);

            File imgFile = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getAbsolutePath(), "/"+filename+"/"+filename+".png");

//Here I thought maybe the resizing of the image or even the image itself
// was causing the hang up so I tried the list without it and it is still 
// hanging.
            //mViewHolder.imageView.setImageURI(Uri.fromFile(new File(imgFile.toString())));
            if (imgFile.exists()){
                /*Bitmap bmp = BitmapFactory.decodeFile(imgFile.toString());
                int newWidth = 500;
                Bitmap sizedBMP = getResizedBitmap(bmp, newWidth);

                mViewHolder.imageView.setImageBitmap(sizedBMP);*/
            }
            else{
                //set no image available
            }

            return convertView;
        }

        private class MyViewHolder {

            TextView posterTitle, posterAuthor, posterSynopsis, posterCategory, posterNumber, posterAltAuthors,posterPresentation;
            ImageView imageView;

            public MyViewHolder(View item) {
                posterTitle = (TextView) item.findViewById(R.id.poster_title);
                posterAuthor = (TextView) item.findViewById(R.id.poster_author);
                posterAltAuthors = (TextView) item.findViewById(R.id.poster_altAuthors);
                posterSynopsis = (TextView) item.findViewById(R.id.poster_synopsis);
                posterCategory = (TextView) item.findViewById(R.id.poster_category);
                posterNumber = (TextView) item.findViewById(R.id.poster_number);
                posterPresentation = (TextView) item.findViewById(R.id.poster_presentation);

                imageView = (ImageView) item.findViewById(R.id.poster_thumb);
            }
        }
    }

我知道那是一大段代码,而且可能很难看。如果您能指出正确的方向来解决问题,那也会很有帮助。我正在使用日食。

我敢打赌,如果您注释掉那行 File imgFile = new File(...(以及依赖于 imgFile 的代码),您的列表滚动将会得到改进。

这仍然是一个 I/O 操作,并且由于 getView() 在 UI 线程中运行,因此可能会出现问题。

你应该做的是:一旦你在 getView() 中有了 ImageView,你就开始 AsyncTask 打开文件,解码它,并将位图分配给 ImageView.

然后你必须处理这样的事情:ImageView被回收了,但是任务还没有完成。

阅读这篇文章:Multithreading for Performance | Android Developers Blog。它处理来自远程服务器的图像,但所有原理仍然相同。

另外:这一行 SparseArray<String> categoryMap = db.getCategoryMap(); 是否进行数据库查找?这也可能导致打嗝。

TL;DR getView() 需要快;将缓慢的操作放在非 UI 线程中。

我同意之前的回答,看起来创建新 File 是唯一挂起您的应用程序的繁重操作。

尝试使用一些图像加载库,例如Glide。它将简化您的代码,您也不必处理后台作业。图书馆会为你做这一切。

1.Import 图书馆,例如如果您使用 gradle 将其插入您的 build.gradle 文件:

repositories {
  mavenCentral() // jcenter() works as well because it pulls from Maven Central
}

dependencies {
  compile 'com.github.bumptech.glide:glide:3.7.0'
  compile 'com.android.support:support-v4:19.1.0'
}

2.In 您的适配器将与加载图片相关的代码替换为:

Glide
    .with(context)
    .load(<full path to your local file>)
    .into(mViewHolder.imageView);

3.And 就这些了。 Glide 将在内部处理回收和其他事情,它还针对快速加载和平滑滚动进行了优化。

图像相关进程确实在应用程序的 UIThread 上消耗了太多内存,您应该使用异步(后台)方法设置图像。或者,如果这对您来说很麻烦,那么有大量的库可以做到这一点。我特别推荐使用 Picasso,因为它非常动态、易于使用并且定期更新。加载图像需要一行代码:

Picasso.with(getApplicationContext()).load(<your image path or url or resource id>).into(YourImageView);

Picasso 也有多种图像选项供您选择。

数据库相关操作应该在单独的线程中完成。因为如果记录数较多,获取数据可能需要时间。

getView() 方法将被调用不止一次。我们可以说它将在循环中调用直到数组列表的大小 (getCount()).

第二件事:文件操作也应该单独完成thread.becauseIO任务也有些耗时。

解法:

SparseArray<String> categoryMap = db.getCategoryMap(); 将这一行放在 getView() 方法之外,因为我在这一行中看不到任何列表相关参数。这应该在 constructorseparate thread.

中完成

运行 您的数据库操作和文件 IO 在单独的线程中使用 AsyncTask