如何提高GridView渲染许多大图像的性能(首次加载时间,滚动平滑度)?

时间:2012-02-02 07:43:33

标签: android performance

我的应用程序允许用户使用他们的设备相机应用程序拍摄照片,这些应用程序将保存到特定于应用程序的文件夹中。

然后,用户可以选择将他们选择的任何图片发送给他们的某个联系人,方法是选择他们的设备电子邮件应用。

Screenshot of "choose images to send" dialog

可悲的是,“选择要发送的图像”对话框最初需要很长时间才能加载,并且在滚动时非常“不稳定”(频繁显示暂停)。我怀疑这是因为图像非常大 - 用我的相机拍摄的照片大约是每个2.3MB。因此,初始屏幕(显示15个图像)需要在磁盘可以渲染之前将其拉出34.5MB左右。

GridView layout.xml

<!-- ... -->
<GridView
android:id="@+id/gvSelectImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:numColumns="3"
android:gravity="center" />
<!-- ... -->

适配器getView()

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    File pic = pics[position];
    View checkedImageView = 
      LayoutInflater.from(context).inflate(R.layout.checked_image, 
                                           parent, false);
    final ImageView imageView = 
      (ImageView) checkedImageView.findViewById(R.id.checkableImage);

    /* LOAD IMAGE TO DISPLAY */
    //imageView.setImageURI(pic.toURI())); // "exceeds VM budget"
    Bitmap image;
    try {
        int imageWidth = 100;
        image = getBitmapFromFile(pic, imageWidth); // TODO: slooow...
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    imageView.setImageBitmap(image);

    /* SET CHECKBOX STATE */
    final CheckBox checkBoxView = 
      (CheckBox) checkedImageView.findViewById(R.id.checkBox);
    checkBoxView.setChecked(isChecked[position]);

    /* ATTACH HANDLERS */
    checkBoxView.setOnCheckedChangeListener(new OnCheckedChangeListener() {
        public void onCheckedChanged(CompoundButton buttonView, 
                                     boolean isChecked) {
            CheckableLocalImageAdapter.this.isChecked[position] = 
              checkBoxView.isChecked();
        }
    });
    imageView.setOnClickListener(new OnClickListener() {
        public void onClick(View v) {
            checkBoxView.setChecked(!checkBoxView.isChecked());
        }
    });

    return checkedImageView;
}

getBitmapFromFile()改编自https://stackoverflow.com/a/823966/633626给出的答案。我注意到那里的代码调用了decodeStream()两次,可能会使我的I / O加倍,但我认为即使我将渲染时间减半,对话框仍然会太慢而且太生涩。

我的测试手机是标准的三星Galaxy S II,如果相关的话。我怀疑旧设备会更慢/更笨。

提高绩效的最佳方法是什么?我猜测AsyncTask的组合加载每个图像(以便对话框可以在渲染所有图像之前加载)和某种缓存(这样滚动不需要重新渲染图像而且不生涩),但我我迷失了如何将这些碎片与其余的拼图相匹配。

2 个答案:

答案 0 :(得分:7)

您希望与thumbnails合作。从SD卡加载整个图像总是很慢。只加载他们真正想要发送的版本的完整版本。

这并不是说缓存和异步加载是个坏主意。我首先更改代码以使用缩略图,重新检查性能,然后转到异步路由。您可以在当前加载的缩略图上显示一个微调器,以指示还有更多内容。

这是一个built-in class来帮助您检索它们。

答案 1 :(得分:2)

尝试使用SampleSize将图像加载到GridView中:

BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 7;
Bitmap bitmap = BitmapFactory.decodeFile(f.getPath(), opts);

有关选项here

的更多信息

此外,您还可以将图像加载交换为Thread或AsyncTask。