Apachi2K Apachi2K - 3 months ago 7
Android Question

Android: Reusing embedded views in gridview [Solution Posted]

I am trying to reuse a framelayout that has an image and textview inside it but I don't think I am doing this right. The code works and the display is right but the performance is very poor and I believe it is because I creating a new ImageView and TextView every time the adapters goes back to the item position.

Can someone tell me how to reuse the embedded ImageView (called i) and TextView (called t) without creating new objects? I am very new to Java and this is my attempt at building a Android application.

public View getView(int position, View convertView, ViewGroup parent) {

FrameLayout F;
FrameLayout ImageBorder;
FrameLayout TextBG;

ImageView i;
TextView t;

if(convertView == null) {
F = new FrameLayout(mContext);

} else {
F = (FrameLayout) convertView;
}

ImageBorder = new FrameLayout(F.getContext());
FrameLayout.LayoutParams params1 = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT,300,Gravity.BOTTOM);
ImageBorder.setLayoutParams(params1);

i = new ImageView(F.getContext());
TextBG = new FrameLayout(F.getContext());
t = new TextView(F.getContext());

F.setBackgroundColor(Color.BLACK);
ImageBorder.setPadding(2, 2, 2, 2);
ImageBorder.setBackgroundColor(Color.BLACK);

FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(FrameLayout.LayoutParams.FILL_PARENT,40,Gravity.BOTTOM);

TextBG.setLayoutParams(params);
TextBG.setBackgroundColor(Color.BLACK);
TextBG.setAlpha(.6f);

t.setLayoutParams(params);

t.setGravity(Gravity.CENTER_VERTICAL);

String pathToPhoto = FileList.get(position).toString();
String fileDescription = pathToPhoto.replaceAll("/mnt/external1/PaliPhotography/","");

fileDescription = fileDescription.replaceAll(".jpg","");
fileDescription = fileDescription.toUpperCase();


Bitmap bm = Cache.getCacheFile("thumb",pathToPhoto);

if (bm == null) {
ImageDownloader downloader = new ImageDownloader(i);
downloader.execute("thumb", pathToPhoto, "400", "400");
} else {

i.setImageBitmap(bm);
i.setScaleType(ImageView.ScaleType.CENTER_CROP);

t.setTextAppearance(getApplicationContext(), android.R.style.TextAppearance_Large);
t.setText(" " + fileDescription);

}

ImageBorder.addView(i);
ImageBorder.addView(TextBG);
ImageBorder.addView(t);

F.addView(ImageBorder);

return F;

}
}


Thank you in advance!

[EDIT]

--------------------------- SOLUTION -----------------------------------------------------

Here is solution that I implemented based on the feedback below! Thank you!

public View getView(int position, View convertView, ViewGroup parent) {

View ReturnThisView;
ViewHolder holder;

LayoutInflater inflater;
holder = new ViewHolder();

if(convertView == null) {
inflater = (LayoutInflater)mContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
ReturnThisView = inflater.inflate(R.layout.imagecell, null);
ReturnThisView.setTag(holder);
} else {
ReturnThisView = convertView;
}

holder.TextDescription = (TextView) ReturnThisView.findViewById(R.id.PhotoDesc);
holder.ImageThumbnail = (ImageView) ReturnThisView.findViewById(R.id.Thumbnail);

String pathToPhoto = FileList.get(position).toString();
String fileDescription = pathToPhoto.replaceAll("/mnt/external1/PaliPhotography/","");

fileDescription = fileDescription.replaceAll(".jpg","");
fileDescription = fileDescription.toUpperCase();

Bitmap bm = Cache.getCacheFile("thumb",pathToPhoto);

if (bm == null) {
ImageDownloader downloader = new ImageDownloader(holder.ImageThumbnail);
downloader.execute("thumb", pathToPhoto, "400", "400");
} else {

holder.ImageThumbnail.setImageBitmap(bm);
holder.ImageThumbnail.setScaleType(ImageView.ScaleType.CENTER_CROP);

holder.TextDescription.setTextAppearance(getApplicationContext(), android.R.style.TextAppearance_Large);
holder.TextDescription.setText(" " + fileDescription);

}

return ReturnThisView;
}
}

static class ViewHolder {
TextView TextDescription;
ImageView ImageThumbnail;
}

Answer
  1. Instead of dynamically creating your View for each element create an XML layout file, say row.xml.
  2. If you detect that convertView == null inflate new row by using inflater
  3. Locate your TextView and ImageView using View#findViewById
  4. Create a Holder object which will help hold references to your newly found TextView and ImageView
  5. Save holder as a tag so convertView.setTag(holder)
  6. For existing convertView find Holder object by doing holder = convertView.getTag()
  7. Set text and image for these two saved objects, e.g. holder.txt.setText("Foo")
  8. Android adapter will do the rest as far as reusing instances of inflated rows

Arguably even for your code you can do view initialization and layout once and use Holder pattern to avoid re-initialization of the elements but I think XML will give you better experience