Hello,
If I understand well the architecture part of Xamarin, manage ressources is more complicated than in android native application, due to MCW.
My application use a lot of Bitmap image, and as I saw on the documentation, I have to help de GC by calling Dispose method or System.GC.Collect(). However, GC.Collect() is an heavy process and can't be call every time, therefore I prefer to use Dispose.
Now, my problem is I have some problem to identify the ressources that are not disposed and must have to be.
First step : Gridview of bitmap.
I display a gridview of bitmap.
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.MainListProductView);
// Find controls
productGridView = FindViewById<GridView>(Resource.Id.lstProducts);
// wire up task click handler
if (productGridView != null)
{
productGridView.ItemClick += (object sender, AdapterView.ItemClickEventArgs e) =>
{
var productDetails = new Intent(this, typeof(DetailsProductActivity));
productDetails.PutExtra("ProductID", products[e.Position].Id);
StartActivity(productDetails);
};
}
}
protected override void OnResume()
{
base.OnResume();
products = ProductManager.Instance.GetAllProducts();
if (products.Count > 0)
{
productList = new Adapters.ProductListAdapter(this, products);
productGridView.Adapter = productList;
if (state != null)
productGridView.OnRestoreInstanceState(state);
}
}
protected override void OnStop()
{
// Save ListView state
state = productGridView.OnSaveInstanceState();
base.OnStop();
}
My list adaptator
public class ProductListAdapter : BaseAdapter<Product>
{
protected Activity context = null;
protected IList<Product> products = new List<Product>();
public ProductListAdapter(Activity context, IList<Product> products)
: base()
{
this.context = context;
this.products = products;
}
public override Android.Views.View GetView(int position, Android.Views.View convertView, Android.Views.ViewGroup parent)
{
// Get our object for position
var item = products[position];
//Try to reuse convertView if it's not null, otherwise inflate it from our item layout
View view = convertView;
if (view == null) {
view = context.LayoutInflater.Inflate(Resource.Xml.productlistitem, null);
// Personalize each item on the View.
view.FindViewById<TextView>(Resource.Id.txtName).Text = AndroidTools.FormatText(item.Name, AndroidTools.TextFormatEnum.TITLECASE, 25);
view.FindViewById<TextView>(Resource.Id.txtPrice).Text = item.Price.ToString() + "$";
// Setting the image
if (item.HasImage())
{
byte[] smallImageByte = Convert.FromBase64String(item.SmallPic);
smallImageByte = Tools.Decompress(smallImageByte);
Bitmap smallPic = BitmapFactory.DecodeByteArray(smallImageByte, 0, smallImageByte.Length);
Drawable dr = new BitmapDrawable(smallPic);
smallPic.Dispose();
smallImageByte = null;
RelativeLayout r = view.FindViewById<RelativeLayout>(Resource.Id.smallPicProduct);
r.SetBackgroundDrawable(dr);
r.Dispose();
dr.Dispose();
}
else
{
/* Android's ListView reuses list items when they aren't need anymore.
* For this reason, you need to make sure all views that should change, will actually get changed.
*/
RelativeLayout r = view.FindViewById<RelativeLayout>(Resource.Id.smallPicProduct);
r.SetBackgroundResource(Resource.Drawable.nopic_small);
r.Dispose();
}
//Finally return the view
}
return view;
}
}
Seems that it's ok, I put all the var to null and dispose all the bitmap ressources....
Second step : detail view of a product
public class DetailsProductActivity : Activity
{
private Product product;
private Bitmap bigPic;
private ImageView pic;
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
// Set our view from the "main" layout resource
SetContentView(Resource.Layout.ProductDetails);
// Get the product
int productID = Intent.GetIntExtra("ProductID", 0);
if (productID > 0)
{
product = ProductManager.Instance.GetProduct(productID);
}
if (product != null)
{
FindViewById<TextView>(Resource.Id.txtName).Text = AndroidTools.FormatText(product.Name, AndroidTools.TextFormatEnum.TITLECASE, 50); ;
FindViewById<TextView>(Resource.Id.txtPrice).Text = product.Price.ToString() + "$";
FindViewById<TextView>(Resource.Id.txtDescription).Text = product.Description;
FindViewById<TextView>(Resource.Id.txtDimensions).Text = product.Width + "x" + product.Height + "x" + product.Depth + product.DimensionsUnit;
FindViewById<TextView>(Resource.Id.txtWeight).Text = product.Weight + product.WeightUnit;
FindViewById<TextView>(Resource.Id.txtAddedTime).Text = Tools.UnixTimeStampToDateTime(product.AddedTime).ToString();
pic = FindViewById<ImageView>(Resource.Id.bigPicProduct);
if (product.HasImage())
{
if (product.BigPic == null)
{
pic.SetImageResource(Resource.Drawable.loading);
suscribe();
ProductManager.Instance.GetBigPicProductAsync(product);
}
else
{
byte[] bigImageByte = Convert.FromBase64String(product.BigPic);
bigImageByte = Tools.Decompress(bigImageByte);
bigPic = BitmapFactory.DecodeByteArray(bigImageByte, 0, bigImageByte.Length);
pic.SetImageBitmap(bigPic);
bigImageByte = null;
bigPic.Dispose();
}
}
}
}
protected override void OnDestroy()
{
pic.Dispose();
base.OnDestroy();
}
#endregion
private void suscribe()
{
ProductManager.Instance.RequestEnded += loadingBigPicFinished;
}
private void unsuscribe()
{
ProductManager.Instance.RequestEnded -= loadingBigPicFinished;
}
private void loadingBigPicFinished(Boolean result, Exception e)
{
unsuscribe();
if (result)
{
product = ProductManager.Instance.GetProduct(product.Id);
byte[] bigImageByte = Convert.FromBase64String(product.BigPic);
bigImageByte = Tools.Decompress(bigImageByte);
bigPic = BitmapFactory.DecodeByteArray(bigImageByte, 0, bigImageByte.Length);
bigImageByte = null;
RunOnUiThread(() =>
{
pic.SetImageBitmap(bigPic);
bigPic.Dispose();
}
);
}
else
{
RunOnUiThread(() => AndroidTools.ShowDialog(this, "Error", e.Message, Finish));
}
}
}
}
Same remarks. But after some browsing, I have a out of memory. So seems that one heavy ressources is not Dispose()ed....
So my question is :
- Is enough to "dispose" bitmap ? Or We have to dispose also other ressources ?
- If is enough, I really don't understand how I can have a out of memory ...
Huge thanks for who will help me because I'm almost resigned to use System.GC.Collect() ....