GridView Performance lag with Custom CursorAdapters - java

I'm currently trying to get the hang of android developemnt and so far its been going good(Well until now). I am currently playing around with Custom Cursor adapters for my grid view. I read using a cursor adapter takes the load of the main UI thread which sounds efficient, so i tried to implement my own cursor adapter as follows
public class VideoListAdapter extends SimpleCursorAdapter{
private Context ctx;
private int parent_layout_id;
ArrayList<VideoModel> videoList = new ArrayList<VideoModel>();
public VideoListAdapter(
Context ctx,
int parent_layout_id,
Cursor c,
String[] fromColumns,
int[] toView)
{
super(ctx,parent_layout_id,c,fromColumns,toView);
this.ctx = ctx;
this.parent_layout_id = parent_layout_id;
}
#Override
public void bindView(View v, Context context, Cursor c) {
//gets title column
int titleColumn = c.getColumnIndex(MediaStore.Video.Media.TITLE);
String title = c.getString(titleColumn);
TextView titleView =(TextView) v.findViewById(R.id.video_title);
titleView.setText(title);
//gets duration
int durationColumn = c.getColumnIndex(MediaStore.Video.Media.DURATION);
String duration = c.getString(durationColumn);
TextView durationView = (TextView) v.findViewById(R.id.video_date);
durationView.setText(duration);
//gets Thumb
int videoDataColumn = c.getColumnIndex(MediaStore.Video.Media.DATA);
String videodataUrl = c.getString(videoDataColumn);
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(videodataUrl);
Bitmap bm = mmr.getFrameAtTime(1000);
ImageView imgv = (ImageView) v.findViewById(R.id.video_thumb);
imgv.setScaleType(ImageView.ScaleType.CENTER_CROP);
imgv.setImageBitmap(bm);
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
Cursor c = getCursor();
//get layout inflater
final LayoutInflater li=LayoutInflater.from(context);
View v = li.inflate(parent_layout_id,parent,false);
//gets title column
int titleColumn = c.getColumnIndex(MediaStore.Video.Media.TITLE);
String title = c.getString(titleColumn);
TextView titleView =(TextView) v.findViewById(R.id.video_title);
titleView.setText(title);
//gets duration
int durationColumn = c.getColumnIndex(MediaStore.Video.Media.DURATION);
String duration = c.getString(durationColumn);
TextView durationView = (TextView) v.findViewById(R.id.video_date);
durationView.setText(duration);
//gets Thumb
int videoDataColumn = c.getColumnIndex(MediaStore.Video.Media.DATA);
String videodataUrl = c.getString(videoDataColumn);
MediaMetadataRetriever mmr = new MediaMetadataRetriever();
mmr.setDataSource(videodataUrl);
Bitmap bm = mmr.getFrameAtTime(1000);
ImageView imgv = (ImageView) v.findViewById(R.id.video_thumb);
imgv.setScaleType(ImageView.ScaleType.CENTER_CROP);
imgv.setImageBitmap(bm);
return v;
}
#Override
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
return super.runQueryOnBackgroundThread(constraint);
}
}
What i'm trying to achieve is to fetch list of video files from the external media storage and display them in a gridview. the standard thumbnails are abit too small for the style of layout i have in mind so i used the MediaMetadataRetriever to fetch frames from each of the video files and used that as thumbnails. Like so
When i ran the application the scroll performance of my gridView worsened. What am I missing. i know the SimpleCursorAdapter class has an overridable method runQueryOnBackgroundThread but i dont even know what to put in there or how to use it. Any pointers will be very much appreciated and forgive my smudge face ;)

First of all bind your Gridview using ViewHolder and second one is save your thumb(bitmap) in existing arrayList so you can not do have to same process while scrolling.

Related

Recyclerview is lagging to much

Here is my code
this is my recyclerview adapter code ..
i dnot konw why my recycler view lagging after schroll
Pleas Help ME
public class Recyclerview1Adapter extends RecyclerView.Adapter<Recyclerview1Adapter.ViewHolder> {
ArrayList<HashMap<String, Object>> _data;
public Recyclerview1Adapter(ArrayList<HashMap<String, Object>> _arr) {
_data = _arr;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater _inflater = getActivity().getLayoutInflater();
View _v = _inflater.inflate(R.layout.video_item, null);
RecyclerView.LayoutParams _lp = new RecyclerView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
_v.setLayoutParams(_lp);
return new ViewHolder(_v);
}
#Override
public void onBindViewHolder(ViewHolder _holder, final int _position) {
View _view = _holder.itemView;
final LinearLayout linear1 = _view.findViewById(R.id.linear1);
final LinearLayout linear2 = _view.findViewById(R.id.linear2);
final LinearLayout linear4 = _view.findViewById(R.id.linear4);
final androidx.cardview.widget.CardView cardview2 = _view.findViewById(R.id.cardview2);
final LinearLayout linear3 = _view.findViewById(R.id.linear3);
final LinearLayout linear7 = _view.findViewById(R.id.linear7);
final ImageView imageview1 = _view.findViewById(R.id.imageview1);
final TextView textview1 = _view.findViewById(R.id.textview1);
final TextView textview2 = _view.findViewById(R.id.textview2);
final LinearLayout linear5 = _view.findViewById(R.id.linear5);
final TextView textview3 = _view.findViewById(R.id.textview3);
final TextView textview4 = _view.findViewById(R.id.textview4);
final LinearLayout linear10 = _view.findViewById(R.id.linear10);
final ImageView imageview3 = _view.findViewById(R.id.imageview3);
_shapeRadius(textview1, "#000000", 6);
_shapeRadius(textview4, "#272731", 8);
textview1.setTypeface(Typeface.createFromAsset(getContext().getAssets(),"fonts/spartan_regular.ttf"), 0);
textview2.setTypeface(Typeface.createFromAsset(getContext().getAssets(),"fonts/spartan_bold.ttf"), 0);
textview3.setTypeface(Typeface.createFromAsset(getContext().getAssets(),"fonts/spartan_regular.ttf"), 0);
textview4.setTypeface(Typeface.createFromAsset(getContext().getAssets(),"fonts/spartan_bold.ttf"), 0);
textview1.setTextSize((int)8);
cardview2.setBackground(new GradientDrawable() { public GradientDrawable getIns(int a, int b) { this.setCornerRadius(a); this.setColor(b); return this; } }.getIns((int)18, 0xFF272731));
duration = Double.parseDouble(allVideosList.get((int)_position).get("videoDuration").toString());
videoDuration = stringForTime((int)duration);
textview1.setText(videoDuration);
path = allVideosList.get((int)_position).get("videoPath").toString();
//using cardview programmatically inside listview is not good. use recyclerview instead of listview.
androidx.cardview.widget.CardView cardview1 = new androidx.cardview.widget.CardView(VideoListFragmentActivity.this.getContext());
cardview1.setCardElevation(0);
cardview1.setCardBackgroundColor(0xFF272731);
cardview1.setRadius(18);
ViewGroup imageParent = ((ViewGroup)imageview1.getParent()); imageParent.removeView(imageview1);
cardview1.addView(imageview1);
imageParent.addView(cardview1);
textview2.setText(Uri.parse(path).getLastPathSegment());
size = Double.parseDouble(allVideosList.get((int)_position).get("videoSize").toString());
humanReadableSize = bytesIntoHumanReadable((long)size);
textview3.setText(allVideosList.get((int)_position).get("formattedDate").toString());
com.bumptech.glide.Glide.with(getContext().getApplicationContext())
.load(path)
.transition(DrawableTransitionOptions.withCrossFade(factory))
.placeholder(R.drawable.video_background)
.error(R.drawable.video_background)
.fitCenter()
.into(imageview1);
textview4.setText(humanReadableSize);
}
#Override
public int getItemCount() {
return _data.size();
}
public class ViewHolder extends RecyclerView.ViewHolder {
public ViewHolder(View v) {
super(v);
}
}
}
Iam trying to create a video player app after adding rcyclerview with glide image loader library , recyclerview is lagging after scroll , get all videos from storage using mediastore then add in a list and add list in recyclerview , but after load more than 100 videos recycler view is lagging to much so please help me .
I think you should try moving stuff from onBindViewHolder to onCreateViewHolder, such as all the setTypeface calls. You shouldn't be calling those every time you bind.
Do you need to create those typefaces for every textview in every viewholder? Maybe you could load those once somewhere else, like in the constructor.
Why are you finding all those linearLayouts in onBindViewHolder? They don't seem to be used in the code.
Ultimately, though, I think most of your latency is probably coming from the
com.bumptech.glide.Glide component, which looks like you are loading a video for each item. You could try creating a test loop that all it does is load all those videos using this component, and time how long it takes.

Why ImageView Not appear image in my app?

i saved photo in server and show it in another place in my app but image doesn't appear in imageview and when i make log.e for url of image url was correct so i don't know why image not appear in imageview any help ????
public CustListMis(Activity context, ArrayList<String> NameArray, ArrayList<String> quantityArray, ArrayList<String> durationArray, ArrayList<String> dTimeArray, ArrayList<String> Images) {
super(context, R.layout.temp_mis, quantityArray);
this.context = context;
this.NameArray = NameArray;
this.quantityArray = quantityArray;
this.durationArray = durationArray;
this.dTimeArray= dTimeArray;
this.Images = Images;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = context.getLayoutInflater();
View listViewItem = inflater.inflate(R.layout.temp_mis, null, true);
TextView name = (TextView) listViewItem.findViewById(R.id.name);
TextView quantity = (TextView) listViewItem.findViewById(R.id.quantity);
TextView duration = (TextView) listViewItem.findViewById(R.id.duration);
TextView dTime = (TextView) listViewItem.findViewById(R.id.dTime);
ImageView myUploadImage = (ImageView)listViewItem.findViewById(R.id.imageyy);
String url = Images.get(position);
// String url = "http://sae-marketing.com/gamaia/PHOTOS/dream.age25#gmail.com-554806.png";
Log.e("image",url);
Picasso.with(context).load(url).noFade().resize(50, 50).centerCrop().into(myUploadImage);
name.setText(NameArray.get(position));
quantity.setText(quantityArray.get(position));
duration.setText(durationArray.get(position));
dTime.setText(dTimeArray.get(position));
return listViewItem;
}
Following OP comments we eventually ended up that the problem was really in the String url variable that does not contains a valid URL string (missing http://).
So the solution ended in doing that:
//String url = "http://sae-marketing.com/gamaia/PHOTOS/dream.age25#gmail.com-554806.png";
String url = "http://" + Images.get(position);
ImageView iv = findViewById(R.id.imageView);
Picasso.with(this).load(url).into(iv);
ou can turn on Picasso logs using
Picasso.with(Context).setLoggingEnabled(true)
You will probably see an error message with a reason there

How can I pass a ListView contaning imageView and textView to other Activity

I have 2 different activities but both of them has a listview. My first activity is empty in terms of data. It just has a button for passing to my second activity.
Each row contains one imageView, textView and checkBox in my second activity.
When I make the checkbox active in my second activity any row, I want to send data to my first activity. For example, I click a checkbox for selecting a line, and when I back in first activity, I should see this line (with ImageView, TextView). Actually, in addition, I want to delete data in first activity when checkbox isn't active. However, I am thinking that I can find this solution if you help me for my first question.
MY FIRST ACTIVITY (I should see rows in here)
ImageView image = (ImageView) findViewById(R.id.image);
Bundle bundleObject = getIntent().getExtras();
if (bundleObject != null) {
String resultText = bundleObject.getString("RESULT_TEXT");
dbHelper.insertNewTask(resultText);
byte[] byteArray = bundleObject.getByteArray("picture");
Bitmap b = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
image.setImageBitmap(b); //ERROR IS HERE!!!!! IT ISN'T WORKING
MY SECOND ACTIVITY
byte[] byteArray;
Bitmap bmp;
int[] images = {R.drawable.book, R.drawable.watchingtv};
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.book);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
bmp.compress(Bitmap.CompressFormat.PNG, 100, stream);
byteArray = stream.toByteArray();
class MyAdapter extends ArrayAdapter<String> implements View.OnClickListener {
Context context;
int[] images;
String[] mytitles;
MyAdapter(Context c, String[] titles, int images[]) {
super(c, R.layout.row_2, R.id.newTaskTitle, titles);
this.context = c;
this.images = images;
this.mytitles = titles;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View row = inflater.inflate(R.layout.row_2, parent, false);
ImageView myImage = (ImageView) row.findViewById(R.id.newImage);
final TextView myTitle = (TextView) row.findViewById(R.id.newTaskTitle);
myImage.setImageResource(images[position]);
myTitle.setText(mytitles[position]);
checkBox = (CheckBox) row.findViewById(R.id.checkBox);
checkBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
#Override
public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
Boolean durum = checkBox.isChecked();
if(durum=true){
Intent intent = new Intent (dinlenmeEkrani_newOptions.this, dinlenmeEkrani.class);
intent.putExtra("picture", byteArray);
intent.putExtra("RESULT_TEXT", myTitle.getText().toString());
startActivity(intent);
}
else{
}
}
});
return row;
}
Second activity might has mistakes. When I try to reach the solution, I might do some mistakes.
I want to say these : I have succeeded in terms of passing textview. So, When I delete some codes related to Image (especially in my first activity), I see passing textView which is coming from String.xml. And also, I just have tried R.Drawable.book because if it works, I think that I can add others drawables.
(if you wonder dbHelper, it is here)
public class Database extends SQLiteOpenHelper
public static final String DB_TABLE = "Task";
public static final String DB_COLUMN = "TaskName";
public void insertNewTask (String task){
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(DB_COLUMN,task);
db.insertWithOnConflict(DB_TABLE,null,values, SQLiteDatabase.CONFLICT_REPLACE);
db.close();
}
Isn't possible to share any view object between activities, because their are linked with the Activity and Activities are completely independent. You need to create a logic to identify and deal with states just passing small pieces of data between activities, like you are already doing with the intent.

Changing color of single drawable in RecyclerView will change all drawables

I just tried to change the color of my drawable inside my row depending on a value but instead of one drawable the adapter changed all of them.
Here is my Adapter:
public class ReportAdapter extends RecyclerView.Adapter<ReportAdapter.ReportViewHolder> {
DataBaseHelper dataBase;
private LayoutInflater inflater;
List<ChoosedSubject> data = Collections.emptyList();
Context context;
OnItemClickListener itemClickListener;
public ReportAdapter(Context context, List<ChoosedSubject> data, OnItemClickListener itemClickListener) {
inflater = LayoutInflater.from(context);
this.data = data;
this.context = context;
this.itemClickListener = itemClickListener;
}
#Override
public ReportViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = inflater.inflate(R.layout.report_cell, parent, false);
ReportViewHolder holder = new ReportViewHolder(view);
dataBase = new DataBaseHelper(context);
return holder;
}
//Set Data inside RecyclerView
#Override
public void onBindViewHolder(ReportViewHolder holder, int position) {
ChoosedSubject current = data.get(position);
Grades grades = new Grades(context);
Resources resources = context.getResources();
int iconColor;
Drawable icon;
icon = ContextCompat.getDrawable(context, dataBase.getSpecificChoosedSubjectAppendingToName(current.getName()).get(0).getChoosedIcon());
if (dataBase.getSpecificChoosedSubjectAppendingToName(current.getName()).get(0).getChoosedIcon() != R.drawable.subject_default) {
iconColor = resources.getColor(dataBase.getSpecificChoosedSubjectAppendingToName(current.getName()).get(0).getChoosedColor());
icon.setColorFilter(iconColor, PorterDuff.Mode.SRC_IN);
holder.icon.setBackground(icon);
} else {
holder.icon.setImageResource(R.drawable.subject_default);
}
holder.subject.setText(current.getName().toString());
NumberFormat formatter = NumberFormat.getNumberInstance();
formatter.setMinimumFractionDigits(0);
formatter.setMaximumFractionDigits(0);
String output = formatter.format(dataBase.getSpecificChoosedSubjectAppendingToName(current.getName()).get(0).getAverage());
int formattedValue = Integer.valueOf(output);
//CHANGING COLOR DEPENDING ON VALUE
int boxColor = 0;
Drawable box = ContextCompat.getDrawable(context, R.drawable.markbox);
Drawable boxBorder = ContextCompat.getDrawable(context, R.drawable.markbox_border);
if (formattedValue >= 10) {
boxColor = resources.getColor(R.color.positive);
} else if (formattedValue >= 4 && formattedValue <= 9) {
boxColor = resources.getColor(R.color.neutral);
} else if (formattedValue < 4) {
boxColor = resources.getColor(R.color.negative);
}
box.setAlpha(204);
box.setColorFilter(boxColor, PorterDuff.Mode.SRC_IN);
boxBorder.setColorFilter(boxColor, PorterDuff.Mode.SRC_IN);
holder.markbox.setImageDrawable(box);
holder.markboxBorder.setImageDrawable(boxBorder);
holder.average.setText(output);
holder.average.setTypeface(EasyFonts.robotoBlack(context));
}
#Override
public int getItemCount() {
return data.size();
}
public class ReportViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
TextView subject;
ImageView icon;
ImageView markbox;
ImageView markboxBorder;
TextView average;
public ReportViewHolder(View itemView) {
super(itemView);
subject = (TextView) itemView.findViewById(R.id.report_subject);
icon = (ImageView) itemView.findViewById(R.id.report_icon);
markbox = (ImageView) itemView.findViewById(R.id.report_markbox);
markboxBorder = (ImageView) itemView.findViewById(R.id.report_markbox_border);
average = (TextView) itemView.findViewById(R.id.report_average);
itemView.setOnClickListener(this);
}
#Override
public void onClick(View v) {
itemClickListener.onItemClick(v, this.getAdapterPosition());
}
}
}
Knows anybody what to do? Thank you for your help!!!
It's sort of caching. From the Android docs:
if you instantiate two Drawable objects from the same image resource, then change a property (such as the alpha) for one of the Drawables, then it will also affect the other. So when dealing with multiple instances of an image resource, instead of directly transforming the Drawable, you should perform a tween animation.
Drawable.mutate() after creating should fix the issue.
A mutable drawable is guaranteed to not share its state with any other drawable. This is especially useful when you need to modify properties of drawables loaded from resources. By default, all drawables instances loaded from the same resource share a common state; if you modify the state of one instance, all the other instances will receive the same modification.
Something like this:
Drawable box = ContextCompat.getDrawable(context, R.drawable.markbox).mutate();
Drawable boxBorder = ContextCompat.getDrawable(context, R.drawable.markbox_border).mutate();
Thanks to Sergey that guided me to the solution. I share what I did in onBindViewHolder method.
final Drawable drawable = ContextCompat.getDrawable(mContext, R.drawable.ic_icon).mutate();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
holder.image.setBackground(drawable);
} else {
holder.image.setBackgroundDrawable(drawable);
}
TL;DR. If you are worried about performance and still want some caching, use TintedIconCache - a single class you can grab from this gist.
TintedIconCache cache = TintedIconCache.getInstance();
Drawable coloredIcon = cache.fetchTintedIcon(context, R.drawable.ic, R.color.color));
How TintedIconCache works?
It manages a cache such that only one instance of a uniquely tinted drawable is kept into memory. It should be fast, and memory efficient.
// Get an instance
TintedIconCache cache = TintedIconCache.getInstance();
// Will be fetched from the resources
Drawable backIcon = cache.fetchTintedIcon(context, R.drawable.icon, R.color.black));
// Will be fetched from the resources as well
Drawable bleuIcon = cache.fetchTintedIcon(context, R.drawable.icon, R.color.bleu));
// Will be fetched from the cache!!!
Drawable backIconTwo = cache.fetchTintedIcon(context, R.drawable.icon, R.color.back));
Check this answer for more details.
Consider looking at the gist to see how it works under the hood.

Set list view height without TextView with adapter

I have a ListView which is supposed to become a menu with two drawables and two text views per row.
Activity Code:
ArrayList<MenuItem> itemArray = new ArrayList<MenuItem>();
itemArray.add(new MenuItem("Headertexxt", "subbtexdt"));
itemArray.add(new MenuItem("asf", "asf"));
ListView listView = (ListView) findViewById(R.id.listViewCM);
String[] array = getResources().getStringArray(R.array.buttonsCM);
int[] images = new int[] { R.drawable.btn_car, R.drawable.btn_star, R.drawable.btn_bag};
listView.setAdapter(new HomeScreenButtonsAdapterSubtext(this, R.layout.row,
itemArray, images, R.drawable.list_arrow));
Utils.setListViewHeightBasedOnChildren(listView);
listView.setOnItemClickListener(new OnItemClickListener() {
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
switch (position) {
case 0:
findViewById(R.id.buttonCreditCompilation).performClick();
break;
case 1:
findViewById(R.id.buttonYourCredits).performClick();
break;
}
}
});
Adapter code:
public class HomeScreenButtonsAdapterSubtext extends ArrayAdapter<MenuItem> {
private Drawable[] drawables;
private Drawable arrowDrawable;
private ArrayList<MenuItem> items;
public HomeScreenButtonsAdapterSubtext(Context context, int resourceId,
ArrayList<MenuItem> items, int[] images, int arrowImage) {
super(context, resourceId, items);
this.items = items;
Resources resources = context.getResources();
if (images != null) {
drawables = new Drawable[images.length];
int i = 0;
for (int id : images) {
Drawable drawable = resources.getDrawable(id);
drawable.setBounds(0, 0, drawable.getIntrinsicWidth(),
drawable.getIntrinsicHeight());
drawables[i++] = drawable;
}
}
arrowDrawable = resources.getDrawable(arrowImage);
arrowDrawable.setBounds(0, 0, arrowDrawable.getIntrinsicWidth(),
arrowDrawable.getIntrinsicHeight());
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = super.getView(position, convertView, parent);
if (v instanceof TextView) {
Drawable dr = drawables != null ? drawables[position %
drawables.length] : null;
((TextView) v).setCompoundDrawables(dr, null, arrowDrawable, null);
Utils.setFont((TextView) v);
}
// View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(R.layout.row, null);
}
MenuItem station = items.get(position);
if (station != null) {
TextView tt = (TextView) v.findViewById(R.id.headerText);
TextView bt = (TextView) v.findViewById(R.id.subText);
if (tt != null) {
tt.setText(station.getHeaderText());
}
if (bt != null) {
bt.setText(station.getSubText());
}
}
return v;
}
The problem I have right now is that I can't set the listview height based on the children. I'm trying to do that here: Utils.setListViewHeightBasedOnChildren(listView); but getting the error: arrayadapter requires the resource id to be a textview at this row. Does anyone know a solution for this?
Can I use some other method for setting the ListView height?
Thanks
but getting the error: arrayadapter requires the resource id to be a
textview at this row.
R.layout.row is a layout file which it doesn't have just a TextView. If you call the super constructor you have used and you also call the super.getView(in the getView method) method in the adapter, then ArrayAdapter will complain as it expects a single widget in the layout file passed to it(a single TextView).
I don't understand why you have that piece of code in the getView method(with the super call) when you know precisely that the row can't be an instance of Textview .
I'm not sure about setting the height of the ListView either, if you're trying to show all the rows of the ListView, don't do it(as you make the ListView basically useless). If you still want to do this, then it's better to lose the ListView and build the row layouts manually.
In fact it does not really make sense to set the height of ListView depending on its content.
Because the whole point of a ListView is to make its content scrollable (however big it is)...so it is supposed to have a fixed height.

Categories