Установка растрового изображения на изображение из byteArray в Xamarin. Android с минимальной нагрузкой на поток пользовательского интерфейса - PullRequest
2 голосов
/ 27 февраля 2020

У меня есть сценарий загрузки растрового изображения в ImageView из byteArray. Для этого я использую следующий код:

Внутри класса, который расширяет ImageView

this.Post(() =>
{
    using (customImage = BitmapFactory.DecodeByteArray(byteArray, 0, byteArray.Count(), options))
    {
        using (var renderBitemap = customImage.Copy(Bitmap.Config.Argb4444, true))
        {
            customImage?.Recycle();
            options.Dispose();
            options = null;
            if (m_pdfParent.undisposedPageImages.Contains(m_pageIndex))
            {
                this.SetImageBitmap(renderBitemap);
            }

        stream = null;
    }
});

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

1) При использовании только метода SetimageBitmap в потоке пользовательского интерфейса => Я получаю исключение, связанное с объектом.

2) При удалении this.Post и запуске всего в фоновом потоке => Я получаю изменение: исключение может изменить только поток, создавший представление.

Есть ли способ улучшить этот фрагмент кода? (Установка растрового изображения из byteArray в ImageView без блокировки потока пользовательского интерфейса)

Ответы [ 3 ]

1 голос
/ 28 февраля 2020

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

class BitmapWorkerTask : AsyncTask<byte[], int, Bitmap>
        {
            private MainActivity mainActivity;

            public BitmapWorkerTask(MainActivity mainActivity)
            {
                this.mainActivity = mainActivity;
            }

            protected override Bitmap RunInBackground(params byte[][] @params)
            {
                return null;

            }

            protected override Java.Lang.Object DoInBackground(params Java.Lang.Object[] native_parms)
            {
                base.DoInBackground(native_parms);
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.InJustDecodeBounds = false;
                Thread.Sleep(4000);
                return BitmapFactory.DecodeByteArray(mainActivity.imageData, 0, mainActivity.imageData.Length, options);
            }

            protected override void OnPostExecute(Bitmap result)
            {
                base.OnPostExecute(result);
                mainActivity.imageView.SetImageBitmap(result);
            }
        }

и вот что-то в MainActivity:

        ImageView imageView;
        byte[] imageData;
        BitmapWorkerTask workerTask;

        protected override void OnCreate(Bundle savedInstanceState)
        {
            base.OnCreate(savedInstanceState);
            Xamarin.Essentials.Platform.Init(this, savedInstanceState);
            // Set our view from the "main" layout resource
            SetContentView(Resource.Layout.activity_main);

            //initialize your byte array imageData here

            imageView = (ImageView)FindViewById(Resource.Id.image);
            workerTask = new BitmapWorkerTask(this);
            workerTask.Execute();
        }

На всякий случай, если вам не нужно загружать точно такой же размер большой картинки, обратитесь к этой странице для эффективной загрузки растрового изображения

1 голос
/ 04 марта 2020

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

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

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

  • Используйте асин c методы для фактического преобразования байтов в битовый массив, используя следующий метод:

    var bmp = await BitmapFactory.DecodeByteArrayAsync(byteArray, 0, byteArray.Count(), options);
    

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

Кроме того, опции не нужно выбрасывать, поскольку они совсем не тяжелые и могут иметь значение G C 'd, когда наступит подходящее время, просто оставьте его, поскольку вы даже можете использовать его позже, если потребуется!

Кроме того, метод recycle для растрового изображения перезапускает ваше растровое изображение er go, делая его бесполезным, и REMEMBER , если элемент пользовательского интерфейса использует это растровое изображение, вы получите исключение объекта, а StackTrace иногда не будет быть ясно, что вызвало это, то есть беспорядок без видимой причины. Лучший способ справиться с этим - чистить свои растровые изображения только тогда, когда вы знаете, что они сейчас бесполезны, т. Е. На уровне страницы, когда вы go переходите на другую страницу, а не когда вы все еще ее используете. Также необходимо повторно обрабатывать вашу страницу, т. Е. Изображение должно быть переназначен таким образом, чтобы указанное выше исключение не генерировалось снова!

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

1 голос
/ 27 февраля 2020

Asyn c & Await - решение вашей проблемы. Возможности AsyncAwait представлены только для того, чтобы избежать проблем, связанных с пользовательским интерфейсом блокировки из-за длительного процесса.

...