列表视图中的性能降低

时间:2014-07-17 10:03:51

标签: android image listview android-asynctask adapter

我的Android应用程序遇到了一个非常奇怪的问题。简单地说,当我将图像内容放入ListView item时就会出现问题。 例如;让我们说我有一个Fragment,其布局如下;

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ListView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:id="@android:id/list" />
</LinearLayout>

我的&#39;列出项目&#39;;

的以下布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp">

    <ImageView
        android:layout_width="@dimen/list_image_width"
        android:layout_height="@dimen/list_image_height"
        android:id="@+id/listimage"
        android:scaleType="centerCrop" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/listtitle"
        android:layout_alignParentTop="true"
        android:layout_toRightOf="@+id/listimage"
        android:layout_alignParentRight="true"
        android:layout_alignParentEnd="true"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:textSize="18sp"
        android:textColor="#000" />

    <TextView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/listsubtitle"
        android:layout_below="@+id/listtitle"
        android:layout_alignRight="@+id/listtitle"
        android:layout_alignEnd="@+id/listtitle"
        android:textSize="17sp"
        android:textColor="#333"
        android:layout_alignBottom="@+id/listimage"
        android:layout_alignLeft="@+id/listtitle"
        android:layout_alignStart="@+id/listtitle" />
</RelativeLayout>

一切顺利。该列表就像我想要的那样呈现出来。但是,每当我开始将图像(内容)放入ImageView时,事情就会变得混乱。无论我做什么,列表加载速度非常慢,滚动几乎是不可能的。 我尝试过多种方式加载图片并将其放入ImageView。 我尝试过的事情:

  • 在自定义ViewHolder中使用Adapter,在AsyncTask文件夹的Drawables中加载图片并将其放入ImageView上的.onPostExecute() {1}}
  • 在自定义ViewHolder中使用Adapter,在不使用Drawables的情况下从AsyncTask加载图片。
  • 使用EasyAdapter,加载DrawablesonSetValues()的图片。
  • 使用EasyAdapter,通过加载`onSetValues()上的Assets文件夹中的图像

所有这些都没有做任何不同的事情,但最后的选择。最后一个选项使列表更容易接受,但仍然加载速度非常慢。 (我按下按钮,fragment被启动,我尝试使用TransactionManager打开它,这似乎只是在显示列表之前冻结应用程序约2-5秒。)滚动更多也可以接受,但仍然没有那么好,应该

如果我将我设置图像的部分注释到ImageView并再次运行,那么该视图绝对没有任何问题。 这一切归结为,设置Drawables文件夹中的内容是不行的。 (虽然我已经为每个我没有问题的应用程序完成了这项工作)。从Assets文件夹设置图像内容可以极大地提高性能,但仍然没有达到我期望的性能。即使使用EasyAdapter,如下所示也是一个可怕的用户体验:

@LayoutId(R.layout.list_default)
public class ListAdapter extends ItemViewHolder<Item> {

    @ViewId(R.id.listimage)
    ImageView image;

    @ViewId(R.id.listtitle)
    TextView title;

    @ViewId(R.id.listsubtitle)
    TextView subtitle;

    public BeetListAdapter(View view) {
        super(view);
    }

    @Override
    public void onSetValues(BeetItem item, PositionInfo positionInfo) {
        title.setText(item.getTitle());
        subtitle.setText(item.getLatinname());
        image.setImageBitmap(getBitmapFromAsset(item.getFirstImageName()));

        getView().setTag(R.id.itemid, item.getId());
    }

    private Bitmap getBitmapFromAsset(String strName)
    {
        AssetManager assetManager = getContext().getAssets();
        InputStream istr = null;
        try {
            istr = assetManager.open("images/" + strName + ".jpg");
        } catch (IOException e) {
            e.printStackTrace();
        }
        Bitmap bitmap = BitmapFactory.decodeStream(istr);
        return bitmap;
    }

}

你们有没有想到为什么会这样?我没有找到任何理由,也没有解决原因。 提前谢谢!

tl; dr 当我将图片放入ListView时,我的ImageView非常慢。它们似乎和来自哪里(ram,磁盘,互联网)并不重要。每当我imageView.setImageBitmap()imageView.setDrawable()时,性能下降和滚动几乎是不可能的。

4 个答案:

答案 0 :(得分:3)

如果可能,请缓存图片,将其缩小Aquery library可以帮助您完成所有这些任务。

答案 1 :(得分:2)

公平地说,以上都没有解决我的问题,我决定实施library that helps with these kinds of problems.

作为参考,这是我初始化 Android Universal Image Loader 的配置;

DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
            .cacheInMemory(true)
            .cacheOnDisk(true)
            .bitmapConfig(Bitmap.Config.RGB_565)
            .imageScaleType(ImageScaleType.EXACTLY)
            .build();

ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
        .defaultDisplayImageOptions(defaultOptions)
        .threadPoolSize(5)
        .threadPriority(Thread.MAX_PRIORITY)
        .tasksProcessingOrder(QueueProcessingType.FIFO)
        .memoryCache(new LruMemoryCache(2 * 1024 * 1024))
        .diskCacheExtraOptions(480, 320, null)
        .build();

ImageLoader.getInstance().init(config);

如果没有实现AsyncTask,我现在在应用程序中有一个非常好的用户体验。

答案 2 :(得分:1)

因为您正在从Main(UI)线程中的资源加载图像,这就是为什么它看起来不稳定。所以像这样在asynktask中加载图像。

public class ListAdapter extends ItemViewHolder<ClipData.Item> {

    @ViewId(R.id.listimage)
    ImageView image;

    @ViewId(R.id.listtitle)
    TextView title;

    @ViewId(R.id.listsubtitle)
    TextView subtitle;

    public BeetListAdapter(View view) {
        super(view);
    }

    @Override
    public void onSetValues(BeetItem item, PositionInfo positionInfo) {
        title.setText(item.getTitle());
        subtitle.setText(item.getLatinname());
        getBitmapFromAsset(item.getFirstImageName(), image);
        getView().setTag(R.id.itemid, item.getId());
    }



    private void getBitmapFromAsset(final String strName,final ImageView imageView)
    {
        new AsyncTask<Void,Void,Bitmap>(){

            @Override
            protected Bitmap doInBackground(Void... voids) {
                try{
                    AssetManager assetManager = getContext().getAssets();
                    InputStream istr = null;
                    try {
                        istr = assetManager.open("images/" + strName + ".jpg");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    Bitmap bitmap = BitmapFactory.decodeStream(istr);
                    return bitmap;
                }catch (Throwable e){
                    e.printStackTrace();
                }
                return null;

            }

            @Override
            protected void onPostExecute(Bitmap result) {
                super.onPostExecute(result);
                if(result!=null){
                    image.setImageBitmap(result);
                }
            }
        }.execute();

    }

}

答案 3 :(得分:0)

不要硬编码LruMemoryCache。因为在某些设备上你会收到:

Fatal signal 11 (SIGSEGV) at 0x00000010 (code=1)

以下是加载图像和滚动列表视图的选项:

DisplayImageOptions defaultOptions = new DisplayImageOptions.Builder()
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .bitmapConfig(Bitmap.Config.RGB_565)
                .imageScaleType(ImageScaleType.EXACTLY)
                .build();
        int memClass;
        memClass = ( (ActivityManager)this.getSystemService( Context.ACTIVITY_SERVICE ) )
                .getMemoryClass();
        ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(getApplicationContext())
                .defaultDisplayImageOptions(defaultOptions)
                .threadPoolSize(1)//from 1-5
                .denyCacheImageMultipleSizesInMemory()
                .threadPriority(Thread.MAX_PRIORITY)
                .tasksProcessingOrder(QueueProcessingType.LIFO)
//                .tasksProcessingOrder(QueueProcessingType.FIFO) /or this
                .memoryCache(new LruMemoryCache(memClass * 1024 * 1024/8))
                .diskCacheExtraOptions(480, 320, null)
                .build();
        ImageLoader.getInstance() .init(config);