I have a LinearLayout
view that already contains several elements. I want to add a lot more Views to it, programmatically. And because this is inside a Scroll
A ListView
is the way to go.
You say that your layout is too complex. But it is completely okay to inflate a complex layout as a child. For example a layout that has text and then an icon:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
Could be inflated in your adapter as so:
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
LinearLayout root = null;
ImageView editImageView;
if (convertView == null) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
root = (LinearLayout)inflater.inflate(R.layout.item, null);
} else {
root = (LinearLayout)convertView;
}
}
You can also be a little more clever in order to support a header. Just add a check if the index is the root and inflate a different view. Since the header is the only one that is different you will still take advantage of all the other rows being reusable. You can even pre-inflate and store the header and reuse it to completely get rid of inflation.
Just use a ListView!
It's the easiest to set up and easiest to maintain. You define an XML layout for the List-Row, and an XML layout for the View which holds the entire List. The ListAdapter does the rest for you.
Just create a:
List<HashMap<String, String>> services = new ArrayList<HashMap<String, String>>();
...and loop through your data to add as many items as you like to the Map. Then set this map to your ListAdapter. Whether 10 items or 100 items the ListAdapter will create a List with that many items.
Example:
public void updateProductList(String searchTerm) {
createOrOpenDB(this);
Cursor cursor = (searchTerm!=null)? dbAdapter.fetchWhere(TBL_NAME, KEY_NAME+" LIKE '%"+searchTerm+"%'")
: dbAdapter.fetchAll(TBL_NAME);
int rows = cursor.getCount();
if (rows<=0) return;
services.clear(); //clear current list
for (int i=0; i<rows; i++) {
HashMap<String, String> map = new HashMap<String, String>();
cursor.moveToPosition(i);
map.put(KEY_NAME, "" + cursor.getString(cursor.getColumnIndex(KEY_NAME)));
map.put(KEY_DESC, "" + cursor.getString(cursor.getColumnIndex(KEY_DESC)));
map.put(KEY_COST, "" + cursor.getDouble(cursor.getColumnIndex(KEY_COST)));
services.add(map);
}
cursor.close();
closeDB();
ListAdapter adapter = new SimpleAdapter(this, services, R.layout.products_view_row,
new String[] {KEY_NAME, KEY_DESC, KEY_COST},
new int[] {R.id.listViewText1, R.id.listViewText2, R.id.listViewText3});
setListAdapter(adapter);
}
3 Options:
Replace everything with a ListView, with the other parent and custom icons as a header view for the ListView. ListView is faster, because it only creates Views as it needs them.
Programatically create the contents of my_list_item instead of inflating, might be quicker
Use of ViewStubs may allow you to load views on-demand.
Maybe it isn't loading the views but the data? in which case prepare the data in a background thread.