Как реализовать галерею изображений (локальные изображения) - PullRequest
4 голосов
/ 20 марта 2012

В настоящее время я делаю приложение для показа изображений с SD-карты. По сути, вы создаете альбом и добавляете в него фотографии, будь то с камеры средства выбора MediaStore.

Я пытался реализовать 2 метода:

  1. Стандартное приложение галереи с пользовательским BaseAdapter для возврата вида
  2. Viewpager с пользовательским PagerAdapter

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

Атм оба метода работают в портретном режиме. Когда я переключаюсь в альбомную ориентацию, некоторые изображения просто сбрасывают

03-20 12:20:56.515: W/OpenGLRenderer(17398): Bitmap too large to be uploaded into a texture

сопровождается ошибками нехватки памяти. Переполнение стека, если оно переполнено проблемами с OOM и галереей, вы должны перезапустить представления, чтобы заставить их работать, потому что convertView всегда равен null в getView из BaseAdapter.

Поэтому я использовал утилиту для просмотра видов, я ограничил ее двумя видами, а портретный режим работал для метода 1 (с использованием галереи). Пейзаж все еще вызывает у меня ту же проблему.

Для метода 2 (viewflipper) он обрабатывает представления по

@Override
public void destroyItem(ViewGroup container, int position, Object object) {

Который никогда не называется кстати ... Однако здесь работает портретный режим. Пейзаж все еще падает.

Мой метод получения растрового изображения:

public static Bitmap getBitmap(Context ctx, int imageId, ImageView target) {

    String file = getPath(ctx, imageId);

    BitmapFactory.Options bmOptions = new BitmapFactory.Options();
    bmOptions.inJustDecodeBounds = true;

    BitmapFactory.decodeFile(file, bmOptions);
    WindowManager mgr = (WindowManager)         ctx.getSystemService(Context.WINDOW_SERVICE);

    int scaleFactor = 1;

    if (mgr != null) {
        // Get the dimensions of the View
        int targetW = mgr.getDefaultDisplay().getWidth();
        int targetH = mgr.getDefaultDisplay().getHeight();
        Log.d(TAG, "Image width + height=" + targetW + "," + targetH);


        int photoW = bmOptions.outWidth;
        int photoH = bmOptions.outHeight;
        // Determine how much to scale down the image
        scaleFactor = Math.min(photoW / targetW, photoH / targetH);

    } else {
        Log.d(TAG, "Target is null");
    }

    // Get the dimensions of the bitmap
    // Decode the image file into a Bitmap sized to fill the View
    bmOptions.inJustDecodeBounds = false;
    bmOptions.inSampleSize = scaleFactor;
    bmOptions.inPurgeable = true;
    logHeap(ImageHelper.class);

    Bitmap bm = BitmapFactory.decodeFile(file, bmOptions);

    if (target != null) {
        target.setImageBitmap(bm);
    }
    return bm;
}

Работает нормально, я знаю, что использую диспетчер окон, чтобы получить размер экрана, но это потому, что мой ImageView по-прежнему имеет размер (0,0), когда я его надуваю. После этого я звоню

imgView.setLayoutParams(new Gallery.LayoutParams(
            Gallery.LayoutParams.FILL_PARENT,
            Gallery.LayoutParams.FILL_PARENT));
    imgView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

Кажется, ничего не работает ...

Пожалуйста, обратите внимание, что я не использую Drawables или любые другие ресурсы, включенные в APK. Эта галерея должна иметь возможность загружать изображения с SD-карты или с камеры в любом качестве, в котором они были сделаны. Очевидно, что галерея должна иметь возможность обрабатывать столько же изображений, сколько имеется в каталоге.

Может кто-нибудь помочь мне ответить на следующие вопросы?

  1. Можно ли как-нибудь сразу сделать галерею по умолчанию полноэкранной и заблокировать вид сетки? Таким образом, мне нужен только адаптер для предоставления изображений, а не для создания собственных представлений. (возможно это решает сбои OOM)
  2. В порядке ли функция декодирования растрового изображения? Мне нужно встроить некоторые хаки, чтобы ловить изменения ландшафта?
  3. Какой лучший способ создать нужную мне галерею, используя пейджер или галерею?
  4. У кого-нибудь есть пример кода полноэкранной галереи, который не вылетает?

1 Ответ

1 голос
/ 23 апреля 2013

Это проблема, с которой я сталкивался несколько раз в прошлом. Google фактически опубликовал статью об этом.

Проблема в inSampleSize, который вы используете для декодирования изображения. Поскольку разные устройства имеют разные экраны и размеры памяти (размеры кучи виртуальных машин могут варьироваться от 12 до 64 и более Мб), вы не можете одинаково декодировать изображения во всех из них. Например, изображение на устройстве 320x240 с динамической памятью 12 МБ должно иметь заданный размер inSampleSize, в то время как на устройстве с динамической памятью 1280x720 64Mb должно использоваться другое inSampleSize (большее).

В статье, на которую я нападаю, показан эффективный способ визуализации изображений для заданной высоты и ширины. Обратите особое внимание на последний сегмент кода, они «предварительно открывают» файл и вычисляют inSampleSize для «полного декодирования» позже.

Я также хотел бы добавить эти рекомендации.

  1. Используйте функцию «getBitmap» в асинхронном режиме, вызовите новый поток или asyncTask (это делается потому, что использование SD занимает много времени, и это приведет к зависанию вашего приложения, замедлению и плохой работе оттиск на устройствах среднего класса.

  2. Старайтесь всегда использовать один и тот же растровый объект. Избегайте создания нескольких «Bitmap bitmap = new Bitmap ()». Вы должны понимать, что загруженные растровые изображения хранятся в оперативной памяти и однажды назначаются представлению, которое становится «сложнее» для сборщика мусора, чтобы получить их.

  3. Когда вы закончите использовать растровое изображение, сделайте его пустым. Для этого представьте, что у вас есть 12Mb max heap RAM. Ваше приложение использует 8 МБ сейчас. Сборщик мусора запускается и не может получить больше неиспользуемой оперативной памяти. 10 быстрых растровых изображений никогда не обнуляют их после назначения данных для ImageView и каким-то образом вы сохраняете их ссылку. Принимая во внимание, что каждое растровое изображение занимает 500 КБ ОЗУ, ваше приложение будет зависать. Всегда делайте растровые изображения пустыми после использования.

  4. Наконец, используйте DDMS, предоставленную в google platform-tools (вы можете получить к нему доступ с помощью eclipse для отладки и просмотра использования памяти, вы также можете заставить сборщик мусора посмотреть, как ваше приложение ведет себя).

...