Заменить вызов setImageResource() на setImageBitmap, чтобы уменьшить сбои?

В документации setImageResource() Android говорится:

Это выполняет чтение и декодирование Bitmap в потоке пользовательского интерфейса, что может вызвать сбой задержки. Если это вас беспокоит, попробуйте вместо этого использовать setImageDrawable(android.graphics.drawable.Drawable) или setImageBitmap(android.graphics.Bitmap) и BitmapFactory.

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

((ImageView) rootView.findViewById(R.id.screen_image)).setImageResource(imageId);

вместо этого позвонить

InputStream is = this.getResources().openRawResource(imageId);
Bitmap imageBitmap = BitmapFactory.decodeStream(is);
((ImageView) rootView.findViewById(R.id.screen_image)).setImageBitmap(imageBitmap);

но сделайте это из другого потока, используя что-то вроде AsyncTask -

Я правильно понимаю или есть более простое решение?

Обновление:

Похоже, существует целый раздел, посвященный эффективному отображению растровых изображений на сайте developer. android.com - я сейчас изучаю это.


person CrimsonX    schedule 11.07.2013    source источник


Ответы (3)


Самый простой способ решить эту проблему — создать рабочий поток как описано в документации по потокам и процессам. Как упоминается, асинхронная задача может быть использована для замены более сложного кода. окончательное решение состояло в том, чтобы изменить мой код в методе OnCreateView(), заменив исходный запаздывающий код:

 final View rootView = inflater.inflate(R.layout.fragment_screen, container, false);
 int i = getArguments().getInt(ARG_PANEL_NUMBER);
 String panel = getResources().getStringArray(R.array.panel_array)[i];
 int imageId = getResources().getIdentifier(panel.toLowerCase(Locale.getDefault()),
                "drawable", getActivity().getPackageName());

 ((ImageView) rootView.findViewById(R.id.screen_image)).setImageDrawable(getResources().getDrawable(imageId));

с новым фоновым потоком:

final View rootView = inflater.inflate(R.layout.fragment_screen, container, false);

// Load image in a separate thread to ensure navigation drawer animation is smooth.
// Replace with Async Task if necessary
    new Thread(new Runnable() {
        public void run() {
            int i = getArguments().getInt(ARG_PANEL_NUMBER);
            final String panel = getResources().getStringArray(R.array.panel_array)[i];

            int imageId = getResources().getIdentifier(panel.toLowerCase(Locale.getDefault()),
                    "drawable", getActivity().getPackageName());

            InputStream is = getActivity().getResources().openRawResource(imageId);
            final Bitmap imageBitmap = BitmapFactory.decodeStream(is);
            rootView.post( new Runnable() {
                public void run() {
                    ((ImageView) rootView.findViewById(R.id.screen_image)).setImageBitmap(imageBitmap);
                    getActivity().setTitle(panel);
                }
            });
        }

    }).start();

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

person CrimsonX    schedule 22.07.2013

Метод setImageResource() немного медленный, потому что он выполняет декодирование в потоке пользовательского интерфейса. Мы можем решить эту проблему, используя рабочий поток или AsyncTaks, но для этого доступно простое и готовое решение. Это библиотека Glide. Вам просто нужно добавить его зависимость в ваш файл gradle как:

compile 'com.github.bumptech.glide:glide:3.7.0'

а затем установите рисуемое изображение, используя его идентификатор как:

Glide.with(context).load(bImage).into(tipImages);

Также могут быть другие библиотеки изображений, такие как Picasso, предоставляющие эту опцию, но здесь я использовал Glide.

person Rahul Sharma    schedule 12.11.2016

Я бы не стал так много в это вчитываться. То, как я интерпретирую это, заключается в том, чтобы просто использовать:

setImageDrawable(getResources().getDrawable(R.id.yourid);

Я вижу еще одну проблему в вашем коде, которая может вызывать сбои. Вы вызываете rootView.findViewById. FindViewById — дорогостоящий вызов, поэтому вы должны сделать это только один раз. Если весь этот код происходит в вашем конструкторе, то все в порядке, но если он находится, например, в методе строки обновления адаптера списка, это может вызвать задержку! Сделайте свой findViewById один раз и назначьте представление переменной-члену.

person athor    schedule 11.07.2013
comment
Код находится в onCreateView для фрагмента. Проблема с задержкой, которую я вижу, связана с использованием примера ящика навигации с кодом здесь: developer.android.com/training/implementing-navigation/ . Когда пользователь нажимает на новую планету, ящик закрывается с дерганной анимацией. Я также задавался вопросом, не лучше ли кэшировать фрагменты и изображения вместо того, чтобы каждый раз извлекать растровое изображение. Кроме того, я попытался использовать приведенную выше строку кода, но анимация все еще не работает. Я попытаюсь переместить этот вызов в конструктор, но не думаю, что это возможно. - person CrimsonX; 12.07.2013