我有一种从byteArray将位图加载到ImageView的方案。我使用以下代码来实现这一目标。
在扩展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;
}
});
您可以看到,位图转换也发生在UI线程中(这是一个繁重的过程,对吗?这会阻塞UI。
1] 仅在UI线程中使用SetimageBitmap
方法打开 =>我得到一个对象处置异常。
2)删除this.Post
并在后台线程中运行所有内容 =>我得到一个例外,即只有创建视图的线程才能更改视图。
有没有一种方法可以改进此代码段?(将位图从byteArray设置为ImageView而不阻塞UI线程)
异步并等待是您解决问题的方法。引入AsyncAwait功能只是为了避免由于长时间运行而导致与阻止UI相关的问题。
您可以使用AsyncTask加载和显示图像,AsyncTask在另一个线程中执行任务,但是一旦任务完成,它将返回UI线程,如下代码:
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();
}
如果不需要加载完全相同的大尺寸图片,请参考此页面的loading bitmap efficiently
由于我无法找到我通常使用的实际代码,因此我将指导您完成整个过程,这应该绰绰有余。
您可以看到,位图转换也发生在UI线程中(这是一个繁重的过程,对吗?这会阻塞UI。
这是正确的,通常来说,位图非常重,可以毫无疑问地导致OOM,因此,处理位图应该是您的最高优先级!,要处理位图,您需要执行以下操作以最大程度地优化它们。速度也很快,而且不会阻塞您的UI。
使用异步方法使用以下方法将字节实际转换为位图:
var bmp = await BitmapFactory.DecodeByteArrayAsync(byteArray, 0, byteArray.Count(), options);
这将不会在UI线程上进行解码,也不会冻结您的应用程序,也不要将其添加到您的using状态,因为当您的Image仍在引用它时,它将被丢弃,这将依次抛出一个例外。
此外,不需要处置这些选项,它们一点也不累赘,可以在适当的时候进行GC处理,因为您甚至可以在以后需要时重用它!
此外,Bitmap的recycle方法回收您的位图使它变得无用,并且REMEMBER如果UI元素正在使用该位图,您将得到对象被处置的异常,并且StackTrace有时不清楚导致它的原因,即没有明显原因的混乱。最好的处理方法是仅当您知道位图现在无用时才对其进行清理,即在转到另一页时在页面级别上,而不是在您仍在使用时对其进行清理,而且还需要处理重新出现的页面,即应重新分配图像,以便不会再次抛出上述异常!
此外,请确保将图像位图优化为View持有者的大小,即确保仅使用以下方法可以在其中使用图像