Android: setImageBitmap vs setImageURI во время прокрутки listview



У меня есть listview с неизвестным количеством пользовательских элементов, и во время прокрутки-внутри getView) я проверяю, существует ли локально связанное изображение с aConvertView и устанавливаю его на элемент listview (aConvertView):



    // out of getView(...)

Bitmap mBitmap;
BitmapFactory.Options mOptions = new BitmapFactory.Options();
mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;


// Inside getView(...)

File file = new File(mContext.getFilesDir(), picture_file_name);
if(file.exists())
{
**// Which one has less impact on the UI thread?**

mBitmap = BitmapFactory.decodeFile(file.getPath(), mOptions);
aImageView.setImageBitmap(mBitmap);

// OR

aImageView.setImageURI(Uri.fromFile(file));
}


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



Является ли setImageBitmap оказывает меньшее влияние на поток пользовательского интерфейса, чем setImageURI? или оба работают на UI и вызывает задержку.



Использует новый файл, Файл.exists() оказывает влияние на поток пользовательского интерфейса?



Излишне говорить, что я использую держатель для моих элементов listview и использовал следующие параметры для моего listview:



        android:smoothScrollbar="true"
android:scrollingCache="false"
android:animationCache="false"
536   3  

3 ответов:

Оба работают в потоке пользовательского интерфейса. Я бы сказал, что первый из них, вероятно, немного быстрее, чем второй. Второй действительно зависит от того, откуда берется ресурс Uri (например, uri может указывать на удаленный файл, который даже не хранится на телефоне).

Я думаю, что вопрос здесь заключается в том, следует ли загружать растровое изображение в поток пользовательского интерфейса, и ответ-нет, особенно в listview. Google опубликовал отличный учебник по developers.android.com о загрузке растровых изображений из потока пользовательского интерфейса: http://developer.android.com/training/displaying-bitmaps/process-bitmap.html

У вас есть проблемы с задержкой, потому что вы делаете файл IO в потоке пользовательского интерфейса, в основном decodeFile является проблемой здесь, где вы на самом деле получить доступ к данным файла на диске (хотя нет никаких причин, чтобы вызвать File.exists() из потока пользовательского интерфейса либо).

Ответ Квантурия верен

Пример там объясняет, как загрузить растровое изображение в фоновом режиме и использовать WeakReference для ImageView, чтобы назначить растровое изображение в качестве фона для рисования. Имейте в виду, что вся ваша работа с файлами IO должна быть внутри doInBackground, onPostExecute на самом деле происходит на Поток пользовательского интерфейса.

EDIT: как использовать файл.Существует () в AsyncTask

// Decode image in background. 
    @Override 
    protected Bitmap doInBackground(Integer... params) {
        File file = new File(mContext.getFilesDir(), picture_file_name);
        if(file.exists())
        { 
           return BitmapFactory.decodeFile(file.getPath(), mOptions);
        }
        else
        {
           return null;
        }
   }

Примечание: у меня нет доступа к моей машине разработки, поэтому я не уверен, что это будет строить.

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

  1. сначала загрузите данные (я предполагаю, что вы используете для этого вызов REST).
  2. из вашего ответа возьмите содержание
  3. Если файл существует, перезаписать
  4. Если файл не существует, создайте

Для меня самое важное-запустить вызов REST и файл IO в фоновом потоке - мне все равно, будет ли это одна задача или две.

Я уже сталкивался с этой проблемой раньше. я пытался загрузить 6 локальных больших изображений (используя Uri) в ListView. Есть 2 вещи, которые вы, вероятно, должны сделать, чтобы ваше приложение работало гладко.

  1. не Загружайте изображение в основной поток. Вот документ android, который как загрузить изображение на отдельный поток: link .Есть много библиотек, которые уже реализуют это для вас. Если вы загружаете изображение из интернета, сервера и т. д. я бы рекомендовалПикассо .

2.Масштабируйте размер изображения, чтобы оно лучше подходило ImageView. Вот документ android о том, как масштабировать размер изображения. Ссылка

В конце концов вот мой AsyncTask класс, который загружает изображение в Новый Поток и масштабирует изображение на основе imageview:

class BitmapWorkerTask extends AsyncTask<Uri, Void, Bitmap> {
    private final WeakReference<ImageView> imageViewReference;
    private Uri data = null;

    public BitmapWorkerTask(ImageView imageView) {
        // Use a WeakReference to ensure the ImageView can be garbage collected
        imageViewReference = new WeakReference<ImageView>(imageView);
    }

    // Decode image in background.
    @Override
    protected Bitmap doInBackground(Uri... params) {
        data = params[0];
        BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        Bitmap bitmap = BitmapFactory.decodeFile(data.toString(),options);
        options.inSampleSize= calculateInSampleSize(options,300,300);
        options.inJustDecodeBounds = false;
        return  BitmapFactory.decodeFile(data.toString(),options);

    }

    // Once complete, see if ImageView is still around and set bitmap.
    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (imageViewReference != null && bitmap != null) {
            final ImageView imageView = imageViewReference.get();
            if (imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }
}
public static int calculateInSampleSize(
        BitmapFactory.Options options, int reqWidth, int reqHeight) {
    // Raw height and width of image
    final int height = options.outHeight;
    final int width = options.outWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {

        final int halfHeight = height / 2;
        final int halfWidth = width / 2;

        // Calculate the largest inSampleSize value that is a power of 2 and keeps both
        // height and width larger than the requested height and width.
        while ((halfHeight / inSampleSize) > reqHeight
                && (halfWidth / inSampleSize) > reqWidth) {
            inSampleSize *= 2;
        }
    }

    return inSampleSize;
}

300*300 - это размер моего изображения

Comments

    Ничего не найдено.