Quantcast
Channel: Recent Threads — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 204402

Complex Image Gallery (viewpager, fragments and dinamic layouts) --> Out of memory

$
0
0

Hello,

I would like to do a complex image gallery (swipe left-right, change image distribution by page, select one image and upload context, ...). I have been looking for a lot of information to do it. I have optimize my code with these posts:

http://forums.xamarin.com/discussion/comment/1233/#Comment_1233

http://developer.android.com/training/displaying-bitmaps/display-bitmap.html

http://developer.android.com/training/displaying-bitmaps/process-bitmap.html

http://docs.xamarin.com/recipes/android/resources/general/load_large_bitmaps_efficiently

...

but the problem continues (out of memory). Attached file (TEST PROJECT).

There is a folder with a lot of images in sdcard. I want show all in any structure.

My solution to do a complex image gallery is:

  • FragmentActivity.
  • 3 fragments (front fragment -> viewpager, two lateral fragments(more information by product)) in FragmentManager.
  • Viewpager
  • Each fragment have x subfragments. (depends images by page).

Code (Attached file)

ViewPager definition

class FragmentViewPager : Fragment { private ViewPager pViewPager;

public ViewPager ViewPager
{
  get { return pViewPager; }
}

public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle bundle)
{
  View v = inflater.Inflate(Resource.Layout.FragmentViewPager, container, false);

  pViewPager = v.FindViewById<ViewPager>(Resource.FragmentViewPager.pager);

  return v;
}

//LLamada desde el activity
public void Init(List<MGeneral.GrupoArticulo> lista)
{
  Adaptador ad = new Adaptador(FragmentManager, lista);
  pViewPager.Adapter = ad;
}

}

public class GrupoArticulo
{
  private int pCodigo;
  private List<string> pArticulos;
  public int Filas, Columnas;

  public int Codigo
  {
    get { return this.pCodigo; }
    set { this.pCodigo = value; }
  }

  public List<string> Articulos
  {
    get { return this.pArticulos; }
    set { this.pArticulos = value; }
  }
}

Adapter

class Adaptador : FragmentStatePagerAdapter { private List<MGeneral.GrupoArticulo> pListaGrupoArticulos;

public Adaptador(Android.Support.V4.App.FragmentManager fm, List<MGeneral.GrupoArticulo> list)
  : base(fm)
{
  this.pListaGrupoArticulos = list;

}

public override Java.Lang.Object InstantiateItem(View p0, int p1)
{
  return base.InstantiateItem(p0, p1);
}

//Actualizas siempre todos los elementos
public override int GetItemPosition(Java.Lang.Object p0)
{
  return PositionNone;
}

public override void StartUpdate(View p0)
{
  base.StartUpdate(p0);
}

public override Fragment GetItem(int position)
{
  MGeneral.GrupoArticulo gf = this.pListaGrupoArticulos[position];

  return Fragmento.Nuevo(gf);      //<------- IMPORTANT
}

public override int Count
{
  get { return this.pListaGrupoArticulos.Count; }
}

}

Fragmento definition

class Fragmento : Fragment { public const string cParametroFilas = "filas"; public const string cParametroColumnas = "columnas"; public const string cParametroArticulos = "articulos";

private int pFilas;
private int pColumnas;
private List<string> pArticulos;

private SubFragmento pSelected;

public int Filas
{
  get { return this.pFilas; }
  set { pFilas = value; }
}

public int Columnas
{
  get { return this.pColumnas; }
  set { pColumnas = value; }
}

public SubFragmento Selected
{
  get { return pSelected; }
}

public static Fragmento Nuevo(MGeneral.GrupoArticulo gf)   //<------- IMPORTANT
{
  Fragmento fragment;
  Bundle bundle;

  fragment = new Fragmento();
  bundle = new Bundle();

  bundle.PutInt(Fragmento.cParametroFilas, gf.Filas);
  bundle.PutInt(Fragmento.cParametroColumnas, gf.Columnas);
  bundle.PutStringArrayList(Fragmento.cParametroArticulos, gf.Articulos.ToArray());

  fragment.Arguments = bundle;

  return fragment;
}

public override Android.Views.View OnCreateView(Android.Views.LayoutInflater inflater, Android.Views.ViewGroup viewGroup, Android.OS.Bundle bundle)
{
  this.pFilas = this.Arguments.GetInt(cParametroFilas);
  this.pColumnas = this.Arguments.GetInt(cParametroColumnas);
  this.pArticulos = new List<string>(this.Arguments.GetStringArrayList(cParametroArticulos));

  return CrearGrupoArticulos();

}

public override void OnActivityCreated(Bundle p0)
{
  base.OnActivityCreated(p0);
}

//Create LAYOUT DINAMICALLY.
//_________________________________
public View CrearGrupoArticulos()
{
  int posicion = 0;


  LinearLayout tableLayout = new LinearLayout(this.Activity);
  tableLayout.Orientation = Orientation.Vertical;
  LinearLayout.LayoutParams parametros = new LinearLayout.LayoutParams(TableRow.LayoutParams.FillParent, TableRow.LayoutParams.FillParent, 1.0f);
  tableLayout.LayoutParameters = parametros;

  LinearLayout LayoutRow;
  SubFragmento Farticulo;

  for (int row = 0; row < this.pFilas; row++)
  {
    LayoutRow = new LinearLayout(this.Activity);
    LayoutRow.Orientation = Orientation.Horizontal;
    LayoutRow.SetBackgroundColor(Color.White);
    parametros = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FillParent, LinearLayout.LayoutParams.FillParent, 1.0f);
    LayoutRow.LayoutParameters = parametros;

    for (int column = 0; column < this.pColumnas; column++)
    {
      Farticulo = new SubFragmento(this.Activity, 1, this.pArticulos[posicion]);   //<------- IMPORTANT
      Farticulo.OnClick += new EventHandler(Farticulo_OnClick);

      LayoutRow.AddView(Farticulo.Vista);
      posicion++;
    }
    tableLayout.AddView(LayoutRow);
  }

  return tableLayout;
}

}

Subfragmento definition

class SubFragmento : Fragment { private TextView txCantidad; private TextView txDescripcion; private ImageButton imArticulo;

private int pCantidad = 0;
private int pUnidadesMedida = 1;
private string pPathImagen = Android.OS.Environment.ExternalStorageDirectory.Path;

private View pView;
private bool pSeleccionado;

int FinalHeight;
int FinalWidth;

public event EventHandler OnClick;

public View Vista
{
  get { return this.pView; }
}

public bool Seleccionado
{
  get { return this.pSeleccionado; }
  set { this.pSeleccionado = value; }
}

public int Cantidad
{
  get { return this.pCantidad; }
}

public SubFragmento(Context context, int unidadesMedida, string articulo)
{
  this.pUnidadesMedida = unidadesMedida;
  this.pPathImagen = System.IO.Path.Combine(this.pPathImagen, "catalog/" + articulo);

  Init(context);
}

/// <summary>
/// Create controls dinamically
/// </summary>
public View Init(Context context)
{

  txDescripcion = new TextView(context);
  RelativeLayout.LayoutParams param = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.FillParent, RelativeLayout.LayoutParams.WrapContent);
  txDescripcion.SetMaxLines(2);
  txDescripcion.LayoutParameters = param;
  txDescripcion.SetTextColor(Color.Black);
  txDescripcion.Text = "042245 Fragance 100ml.";

  imArticulo = new ImageButton(context);
  LinearLayout.LayoutParams params2 = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FillParent, LinearLayout.LayoutParams.FillParent, 1.0f);
  imArticulo.LayoutParameters = params2;
  imArticulo.SetBackgroundColor(Color.White);
  imArticulo.Click += new EventHandler(imArticulo_Click);

  txCantidad = new TextView(context);
  RelativeLayout.LayoutParams param3 = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WrapContent, RelativeLayout.LayoutParams.WrapContent);
  param3.AddRule(LayoutRules.AlignParentRight);
  txCantidad.SetBackgroundColor(Color.Black);
  // use same id as defined when adding the button  
  txCantidad.LayoutParameters = param3;
  txCantidad.SetTextSize(Android.Util.ComplexUnitType.Dip, 24);

  RelativeLayout layout = new RelativeLayout(context);
  layout.SetBackgroundColor(Color.White);
  layout.LayoutParameters = new RelativeLayout.LayoutParams(LinearLayout.LayoutParams.FillParent, RelativeLayout.LayoutParams.WrapContent);
  layout.AddView(imArticulo);
  layout.AddView(txCantidad);
  layout.AddView(txDescripcion);

  LinearLayout main = new LinearLayout(context);
  main.LayoutParameters = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.FillParent, LinearLayout.LayoutParams.FillParent, 1.0f);
  main.AddView(layout);

  this.pView = main;

  //Upload width / height dinamically to change fragme imagebutton
  ViewTreeObserver vto = imArticulo.ViewTreeObserver;
  vto.GlobalLayout += (sender, args) =>
  {
    if (imArticulo.Width != FinalWidth || imArticulo.Height != FinalHeight)
    {
      FinalWidth = imArticulo.Width;
      FinalHeight = imArticulo.Height;

      LoadImage();  //<------- IMPORTANT
    }
  };

  return main;
}

private void LoadImage()
{
  Bitmap bitmap;

  MGeneral.pLRUCache.TryGetValue(this.pPathImagen, out bitmap);

  if (bitmap != null)
  {
    imArticulo.SetImageBitmap(bitmap);
    //bitmap = null;
  }
  else
  {
    MGeneral.BitmapWorkerTask task = new MGeneral.BitmapWorkerTask(imArticulo, 1, FinalWidth , FinalHeight);
    task.Execute(this.pPathImagen);
  }
}

Load image in imagebutton

public class BitmapWorkerTask : AsyncTask
{
  private WeakReference imageViewReference;
  private int sampleSize = 0;
  private int reqHeight = 0;
  private int reqWidht = 0;
  private string path;

  public BitmapWorkerTask(ImageButton imageView, int pSampleSize, int pReqWidth, int pReqHeight)
  {
    //_____________________________________________________________________
    // Use a WeakReference to ensure the ImageView can be garbage collected
    imageViewReference = new WeakReference(imageView);

    reqHeight = pReqHeight;
    reqWidht = pReqWidth;
    sampleSize = pSampleSize;
  }

  protected override Java.Lang.Object DoInBackground(params Java.Lang.Object[] @params)
  {
    path = @params[0].ToString();

    try
    {
      //return DecodeSampleBitmapFromFile(path, reqWidht, reqHeight);
      return DecodeSampleBitmapFromFile(path, reqWidht, reqHeight);
    }
    catch (System.Exception ex)
    {
      Log.Debug("TT", "Exception : " + ex.Message);
      return null;
    }
  }

  protected override void OnPostExecute(Java.Lang.Object result)
  {
    base.OnPostExecute(result);

    if (IsCancelled)
    {
      result = null;
      Log.Debug("TT", "OnPostExecute - Task Cancelled");
    }
    else
    {
      using (Bitmap bmpResult = result as Bitmap)
      {
        if (imageViewReference != null && bmpResult != null)
        {
          ImageButton view = imageViewReference.Target as ImageButton;

          if (view != null)
          {
            view.SetImageBitmap(bmpResult); //Actualizo el imagebutton con el bitmap resultante.
            if (!pLRUCache.ContainsKey(path))
              pLRUCache.Add(path, bmpResult);  //Añado el bitmap en la cache de imagenes.
          }
        }
      }
    }
  }

  public static int CalculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight)
  {
    //_____________________________
    // Raw height and width of image
    int height = options.OutHeight;
    int width = options.OutWidth;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth)
    {
      if (width > height)
      {
        inSampleSize = (int)System.Math.Round((float)height / (float)reqHeight);
      }
      else
      {
        inSampleSize = (int)System.Math.Round((float)width / (float)reqWidth);
      }
    }

    return inSampleSize;

  }

  public static Bitmap DecodeSampleBitmapFromFile(string path, int reqWidth, int reqHeight)
  {

    try
    {
      //______________________________________________________________
      // First decode with inJustDecodeBounds=true to check dimensions
      BitmapFactory.Options options = new BitmapFactory.Options();
      options.InJustDecodeBounds = true;
      BitmapFactory.DecodeFile(path, options);
      //BitmapFactory.DecodeStream(url.OpenConnection().InputStream, null, options);

      //______________________
      // Calculate inSampleSize
      options.InSampleSize = CalculateInSampleSize(options, reqWidth, reqHeight);

      //____________________________________
      // Decode bitmap with inSampleSize set
      options.InJustDecodeBounds = false;
      return BitmapFactory.DecodeFile(path, options);
    }
    catch (System.Exception ex)
    {
      Log.Debug("DecodeBitmapFromFile: ", ex.Message);
      return null;
    }
    finally
    {
      //
    }
  }

}

Thanks


Viewing all articles
Browse latest Browse all 204402

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>