Как улучшить производительность (время первой загрузки, плавность прокрутки) GridView, отображающего много больших изображений? - PullRequest
3 голосов
/ 02 февраля 2012

Мое приложение позволяет пользователям делать фотографии с помощью приложения камеры на своих устройствах, которые сохраняются в папке приложения.

Затем пользователи могут отправить любое изображение по своему усмотрению одному из своих контактов, используя приложение электронной почты для своих устройств.

Screenshot of

К сожалению, диалоговое окно «выбрать изображения для отправки» изначально загружается очень долго и очень «прерывисто» (частые заметные паузы) при прокрутке. Я подозреваю, что это потому, что изображения очень большие & mdash; снимки, сделанные моей камерой, составляют около 2,3 МБ каждая. Поэтому на начальном экране (отображаемом 15 изображений) необходимо отвести с диска около 34,5 МБ, прежде чем он сможет отрисоваться.

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() и может удвоить мой ввод / вывод, но я думаю, что диалог все равно будет слишком медленным и слишком вяло, даже если я вдвое уменьшу время рендеринга.

Мой тестовый телефон - это стандартный Samsung Galaxy S II, если это актуально. Я подозреваю, что старые устройства будут еще медленнее / чоппер.

Какой лучший способ улучшить производительность здесь? Я предполагаю комбинацию AsyncTask для загрузки каждого изображения (чтобы диалог мог загружаться до рендеринга всех изображений) и какое-то кэширование (чтобы прокрутка не требовала перерисовки изображений и не была прерывистой), но я Я заблудился о том, как совместить эти кусочки с остальной частью моей головоломки.

Ответы [ 2 ]

7 голосов
/ 02 февраля 2012

Вместо этого вы захотите работать с миниатюрами .Загрузка всего изображения с SD-карты всегда будет медленной.Загружайте только полную версию того, что они действительно хотят отправить.

Это не значит, что кэширование и асинхронная загрузка - плохая идея.Я бы изменил код, чтобы он сначала работал с миниатюрами, перепроверил производительность, а затем пошел бы по асинхронному маршруту.Вы можете показать небольшую вертушку над загружаемой в данный момент миниатюрой, чтобы указать, что это еще не все.

Вот встроенный класс , который поможет вам найти их.

2 голосов
/ 02 февраля 2012

Попробуйте загрузить изображения с размером образца в GridView:

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

Подробнее о параметрах здесь

А также вы можете поменять местами загрузку изображения в Thread или AsyncTask.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...