I have a listview which loads its data from sqlite database.
Each row in listview has image , textview and a checkbox.
The sqlitedatabase rows has image and text data + some other columns.
My question is can I bind my listview with the database so that all rows will be loaded with required data automatically. (image + textview) There are examples to bind a simple list of textviews. What about complex rows ? Also there are few spinners which can filter the data in list depending on its value. (Which act as a WHERE clause on my DB)
Currently I am managing this all by generating the view for my custom adapter for each row. So each time I query database and populate data. I hold the last listview results , make a newer results based on actions/conditions like spinner values, then notifydatachanged to adapter to load my new results.
To add features like DELETE , ADD , SEARCH -- I have to manage it all using collections.
Is there any simple way of doing this ? As if the db is large then the approach of holding such huge set of results in memory is not good. And is painful for managing it.
Thanks.
Here is my example for row, constructed from two records from db + image (at current - one image for any row, but it can be improved for specific image from db):
public class DomainAdapter extends SimpleCursorAdapter{
private Cursor dataCursor;
private LayoutInflater mInflater;
....
public DomainAdapter(Context context, int layout, Cursor dataCursor, String[] from,
int[] to) {
super(context, layout, dataCursor, from, to);
this.dataCursor = dataCursor;
mInflater = LayoutInflater.from(context);
}
public View getView(int position, View convertView, ViewGroup parent) {
// A ViewHolder keeps references to children views to avoid unneccessary calls
// to findViewById() on each row.
ViewHolder holder;
// When convertView is not null, we can reuse it directly, there is no need
// to reinflate it. We only inflate a new View when the convertView supplied
// by ListView is null.
if (convertView == null) {
convertView = mInflater.inflate(layout, null);
// Creates a ViewHolder and store references to the two children views
// we want to bind data to.
holder = new ViewHolder();
holder.text1 = (TextView) convertView.findViewById(R.id.test_track);
holder.text2 = (TextView) convertView.findViewById(R.id.test_band);
holder.icon = (ImageView) convertView.findViewById(R.id.test_artwork);
convertView.setTag(holder);
} else {
// Get the ViewHolder back to get fast access to the TextView
// and the ImageView.
holder = (ViewHolder) convertView.getTag();
}
// Bind the data efficiently with the holder.
// Cursor to current item
dataCursor.moveToPosition(position);
int title_index = dataCursor.getColumnIndex(fields[0]);
String title = dataCursor.getString(title_index);
int description_index = dataCursor.getColumnIndex(fields[1]);
String description = dataCursor.getString(description_index);
holder.text1.setText(title);
holder.text2.setText(description);
holder.icon.setImageResource(R.drawable.alert_dialog_icon);
return convertView;
}
static class ViewHolder {
TextView text1;
TextView text2;
ImageView icon;
}
}
and using this adapter:
databaseListAdapter = new DomainAdapter(this,
R.layout.test_layout,
databaseCursor,
new String[] {"title", "description"},
new int[] { R.id.test_track, R.id.test_track });
databaseListAdapter.notifyDataSetChanged();
DomainView.setAdapter(databaseListAdapter);
and layout:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="64dip"
android:padding="6dip">
<TextView
android:id="#+id/test_band"
android:layout_width="fill_parent"
android:layout_height="26dip"
android:layout_below="#+id/test_track"
android:layout_alignLeft="#id/test_track"
android:layout_alignParentBottom="true"
android:gravity="top" />
<TextView
android:id="#id/test_track"
android:layout_marginLeft="6dip"
android:layout_width="fill_parent"
android:layout_height="26dip"
android:layout_toRightOf="#+id/test_artwork"
android:textAppearance="?android:attr/textAppearanceMedium"
android:gravity="bottom" />
<ImageView
android:id="#id/test_artwork"
android:layout_width="56dip"
android:layout_height="56dip"
android:layout_gravity="center_vertical" />
</RelativeLayout>
My question is can I bind my listview
with the database so that all rows
will be loaded with required data
automatically. (image + textview)
There are examples to bind a simple
list of textviews. What about complex
rows ?
Yes, you can do a Cursor to complex view mapping by implementing your own CursorAdapter and overriding the bindView().
Related
I use bindView() method is custom CursorAdapter implementation to dynamically add text views to a list.
Each list item is represented by list_item layout which contains flow_layout layout from Android Flowlayout
<!--List Item Layout-->
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="#dimen/activity_vertical_margin"
android:background="#FFFFFF">
<!--Flow Layout-->
<org.apmem.tools.layouts.FlowLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="#dimen/view_padding"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:id="#+id/hash_tag_layout"
>
</org.apmem.tools.layouts.FlowLayout>
</LinearLayout>
The number of text views added to flow_layout per each instance of list item reflects the number of row values returned in the cursor.
public void bindView(View view, Context context, Cursor cursor) {
// Flow layout wraps new views around the screen.
FlowLayout flowLayout = (FlowLayout) view.findViewById(R.id.flow_Layout);
// getRowValues() puts row values from cursor into an array list.
ArrayList<> rowValues = getRowValues(cursor);
// A new text view is created and inserted into Flow layout
// for each value in rowValues
TextView tv;
for value in rowValues {
tv = = new TextView(ctx);
tv.setText(value);
flowLayout.addView(tv);
}
}
To re-iterate, I want the number of text views inside each flow_layout per each instance of list_item to reflect the number of row values returned by the cursor.
However, every time I re-scroll over a list item, the number of text views in that particular item doubles, and additionaly, binded data sometimes does the reflect symetrically between the position of the cursor and the position of the list item. I think the problem is related to the recycling of old text views.
How can I prevent new text views from stacking onto old textviews? Is it possible to override view recycling in custom cursor adapter for specific child views, and force garbage collection them when they go off screen?
Here is full implemtation of custom cursor adapter
public class DatabaseAdapter extends CursorAdapter {
Context ctx;
public DatabaseAdapter(Context context, Cursor cursor, int flags) {
super(context, cursor, 0);
ctx = context;
}
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = LayoutInflater.from(context).inflate(R.layout.list_item, parent, false);
return v;
}
public void bindView(View view, Context context, Cursor cursor) {
// Flow layout wraps new views around the screen.
FlowLayout flowLayout = (FlowLayout) view.findViewById(R.id.flow_Layout);
// getRowValues() puts row values from cursor into an array list.
ArrayList<> rowValues = getRowValues(cursor);
// A new text view is created and inserted into Flow layout
// for each value in rowValues array list
TextView tv;
for value in rowValues {
tv = = new TextView(ctx);
tv.setText(value);
flowLayout.addView(tv);
}
}
}
if(flowLayout.getChildCount() > 0)
flowLayout.removeAllViews();
I am developing an extremely simple list app to save items to an SQLite DB, and populate a ListView with it's contents.
This can be done using a SimpleCursorAdapter, which I do like this:
mySQLiteAdapter.openToRead();
cursor = mySQLiteAdapter.queueAll();
String[] from = new String[]{mySQLiteAdapter.getKeyContent()};
int[] to = new int[]{R.id.normal};
cursorAdapter = new SimpleCursorAdapter(this, R.layout.row, cursor, from, to, 0);
listView.setAdapter(cursorAdapter);
mySQLiteAdapter.close();
Now however I would like to implement the ability to either strike out text on a row by click or long click, or change the row to a different layout (which could also strike the text)
At first I simply set the onClickListener for the listview and changed the paint flags to strike the text. This works fine until there are enough items in the list to scroll the view, or until the activity is reloaded. In the latter the strike is gone (since nothing was persistent), and in the former other rows are striked, and the intended ones are not. Then is changes as you scroll around. See Custom ListView adapter, strange ImageView behavior for a similar situation to my own.
From this I have found that I will need use a custom adapter to do what I want. So I have created a CustomCursorAdapter which extends SimpleCursorAdapter and overriden some methods to attempt to inflate a seperate layout with a background colour. I am not having much luck.
Here is what I have so far:
// Creating a new instance of the custom adapter and assigning it to the listview
mySQLiteAdapter.openToRead();
cursor = mySQLiteAdapter.queueAll();
String[] from = new String[]{mySQLiteAdapter.getKeyContent()};
int[] to = new int[]{R.id.normal};
cursorAdapter = new CustomCursorAdapter(this, R.layout.row, cursor, from, to, 0);
listView.setAdapter(cursorAdapter);
mySQLiteAdapter.close();
and
// CustomCursorAdapter class
private class MyCursorAdapter extends SimpleCursorAdapter {
private LayoutInflater inflater;
public MyCursorAdapter(Context context, int layout, Cursor c, String[] from, int[] to, int flags) {
super(context, layout, c, from, to, flags);
inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Get reference to the row
View view = super.getView(position, convertView, parent);
//View view;
if (getItemViewType(position) == 0) {
view = inflater.inflate(R.layout.row, null);
}
else {
view = inflater.inflate(R.layout.rowstrike, null);
}
return view;
}
#Override
public int getItemViewType(int position) {
int row;
if (cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyStrike())) == 1) {
Log.d("DEBUG", "Row " + position + " is STRIKED");
row = 1;
}
else {
Log.d("DEBUG", "Row " + position + " is normal");
row = 0;
}
return row;
}
}
The implementation of the CustomCursorAdapter works and shows the correct amount of rows. The logic to determine if the row should contain striked text by querying the db is correct, however the returned inflated views are completely blank. I think it may be to do with the way my XML files are arranged and which ones I pass to the adapter but all my testing and tinkering to try to get this working have failed spectacularly so far.
Here are my XML files for the layouts
// activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
android:paddingBottom="#dimen/activity_vertical_margin"
tools:context=".MainActivity">
<EditText
android:layout_width="fill_parent"
android:layout_height="35dp"
android:id="#+id/editText"
android:hint="Press here to add an item"
android:maxLines="1"
android:imeOptions="actionDone"
android:inputType="textAutoCorrect"/>
<ListView
android:layout_width="match_parent"
android:layout_height="fill_parent"
android:id="#+id/listView"
android:layout_below="#id/editText"/>
</RelativeLayout>
.
// row.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp" >
<TextView
android:id="#+id/normal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textStyle="bold"/>
</RelativeLayout>
.
//rowstrike.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="5dp" >
<TextView
android:id="#+id/striked"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#F05"/>
</RelativeLayout>
I have been searching on this for days and days, each time getting closer but nothing seems to work, or the explanations are not beginner friendly for someone like myself.
The closest post I have found to what I am after is
ListView view recycling with CustomAdapter
However I think I need more code snippets as I must be doing something wrong elsewhere in my app?
There is a mention of overriding the getViewTypeCount method but I am unsure of how this is done...
There is also
How would I use a different row layout in custom CursorAdapter based on Cursor data?
However I am not quite sure where to go from this post...
EDIT: Solution based on Luksprogs post.
mySQLiteAdapter.openToRead();
cursor = mySQLiteAdapter.queueAll();
String[] from = new String[]{mySQLiteAdapter.getKeyContent()};
int[] to = new int[]{R.id.normal};
cursorAdapter = new SimpleCursorAdapter(this, R.layout.row, cursor, from, to, 0);
cursorAdapter.setViewBinder(new SimpleCursorAdapter.ViewBinder() {
#Override
public boolean setViewValue(View view, Cursor cursor, int columnIndex) {
if (view.getId() == R.id.normal) {
TextView tv = (TextView)view.findViewById(R.id.normal);
if (cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyStrike())) == 1) {
tv.setPaintFlags(tv.getPaintFlags() | Paint.STRIKE_THRU_TEXT_FLAG);
}
else {
tv.setPaintFlags(tv.getPaintFlags() & (~Paint.STRIKE_THRU_TEXT_FLAG));
}
}
return false;
}
});
listView.setAdapter(cursorAdapter);
mySQLiteAdapter.close();
and I have an OnItemClickListener as follows to strike and unstrike rows
private ListView.OnItemClickListener listViewOnItemClickListener
=new ListView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
final int rowID = cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyID()));
mySQLiteAdapter.openToWrite();
if (cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyStrike())) == 0) {
mySQLiteAdapter.setKeyStrike(rowID, 1);
}
else {
mySQLiteAdapter.setKeyStrike(rowID, 0);
}
cursor = mySQLiteAdapter.queueAll();
cursorAdapter.swapCursor(cursor);
mySQLiteAdapter.close();
};
however the returned inflated views are completely blank.
As a side note, you shouldn't override the getView() method of a Cursor based adapter because this type of adapters implemented getView() to separate building the row layout and binding the data in two separate methods, newView() and bindView(). This two methods should be overridden. Also, SimpleCursorAdapter is a class designed for basic scenarios, if you need to implement (really) different row types then extending CursorAdapter would be a better approach.
You get blank row layouts because you don't do any data binding on them. In the getView() method you do:
View view = super.getView(position, convertView, parent);
which will return you a properly built row layout(by the SimpleCursorAdapter class implementation)only to discard that view and inflate a new row layout based on the row type(the if-else piece of code). You don't bind any data to those views so you return just the inflated layout which will be blank.
If your two rows are only different by a strikethrough text then you shouldn't be using two row types(different row types should be used when the rows are different in structure). You could implement what you want through a ViewBinder:
cursorAdapter = new SimpleCursorAdapter(this, R.layout.row, cursor, from, to, 0);
cursorAdapter.setViewBinder(new ViewBinder() {
#override
public void setViewValue(View view, Cursor cursor, int columnIndex) {
if (view.getId() == R.id.normal) {
// I'm assuming that the TextView with the id R.id.normal
// is the on to strike through
// use the cursor to get the value from the column on which you
// do the strikethrough
if (cursor.getInt(cursor.getColumnIndex(mySQLiteAdapter.getKeyStrike()) == 1) {
// strike the text
} else {
// otherwise un-strike the text
}
}
return false;
}
});
listView.setAdapter(cursorAdapter);
If you want
I would like to implement the ability to either strike out text on a
row by click or long click
Then you need to remember the row status somewhere so you can use it to restore it.
I have a android listview and it has a two_line_list_item layout.... text1 and text2
I have a SQL query which returns me my Cursor.... in the below example I have set NameA from the SQL to text1 and NameB to text2
// Create an array to specify the fields we want to display in the list (only TITLE)
String[] from = new String[]{"NameA", "NameB"};
// and an array of the fields we want to bind those fields to (in this case just text1)
int[] to = new int[]{android.R.id.text1, android.R.id.text2};
// Now create a simple cursor adapter and set it to display
SimpleCursorAdapter matches = new SimpleCursorAdapter(this, android.R.layout.two_line_list_item, MatchesCursor, from, to);
setListAdapter(matches);
How could I go about concatenating the two names (without changing my SQL query) so text1 will be "NameA v NameB"...
Thanks in advance
In your Query do
NameA || "v" || NameB AS NameAB
Then remove the second textView (android.R.text2)
In your return projections put "NameAB" leave out the other columns (keep KEY_ID) as you will no longer be needing them.
It seems to me that you need to write custom Adapter which extends BaseAdapter.
A dirty way would be using 3 views in your xml:
<TextView
android:id="#+id/nameA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30dp" />
<TextView
android:id="#+id/separator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=" vs "
android:textSize="30dp" />
<TextView
android:id="#+id/nameB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="30dp" />
wrapping everything in a horizontal LinearLayout.
You need to write your own adapter that extends BaseAdapter
public class CustomAdapter extends BaseAdapter {
private Context context;
private int listItemLayout;
private String[] nameAs;
private String[] nameBs;
public CustomAdapter(Context context, int listItemLayout, String[] nameAs, String[] nameBs) {
this.context = context;
this.listItemLayout = listItemLayout;
this.nameAs = nameAs;
this.nameBs = nameBs;
}
#Override
public View getView(final int position, View convertView, ViewGroup parent) {
if(convertView==null)
convertView = LayoutInflater.from(context).inflate(listItemLayout, null);
TextView textView1 = (TextView)findViewById(android.R.id.text1);
textView1.setText(nameAs[position] + " v " + nameBs[position]);
return convertView;
}
}
Now all you need to do is to modify a bit of your database access function to return you the two arrays of names, and pass them to the constructor of CustomAdapter
Eventually, call:
CustomAdapter myAdapter = new CustomAdapter(this, android.R.layout.two_line_list_item, nameAs, nameBs);
setListAdapter(myAdapter);
As a note, please also try to follow the ViewHolder pattern suggested in the link.
I have the layout:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ListView
android:id="#+id/ListView01"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_weight="1.0"
android:textColor="#android:color/white"
android:dividerHeight="1px"
android:listSelector="#drawable/highlight_sel"
/>
</LinearLayout>
And the code:
private ListView lv1;
private String lv_arr[]={"Item 1","Item 2","Item 3","Item 4"};
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.newsmenu);
lv1=(ListView)findViewById(R.id.ListView01);
// By using setAdpater method in listview we an add string array in list.
lv1.setAdapter(
new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1,
lv_arr));
}
I want the text color of Item 2 (or 1 or 3 or 4) to appear dynamically as red (denoting a new item) or white (default). Is there a way to do this?
I already have a selector present, which is why I used ListView. I've search the Internet and this site, and I have not seen this question broached.
So is it possible?
Yes everything is possible. you need to write your own adapter implementation basically overriding the getView Method in the adapter. search google and stack you will find many tutorials on how to write an adapter.
Writing a special adapter to override getView in simple adapter is the way to change the text color alternating on the lines of your choice in a listview. I took the example which has been repeated many times on this website and added a way to change the text color. position mod length to select the color position can be replaced with any scheme you like. The text view "business" can be the first line of your layout like mine--or use the android.R.id.text1.
public class SpecialAdapter extends SimpleAdapter {
private int[] colors = new int[] { 0x30FF0000, 0x300000FF };
public SpecialAdapter(Context context, List<HashMap<String, String>> items, int resource, String[] from, int[] to) {
super(context, items, resource, from, to);
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
int colorPos = position % colors.length;
//view.setBackgroundColor(colors[colorPos]); //old example
TextView tv1 = (TextView)view.findViewById(R.id.business); //new
tv1.setTextColor(colors[colorPos]); //new
return view;
}
}
Just use SpecialAdapter instead of SimpleAdapter in your app.
Here's an example of a getView method. Note that it's using a viewholder for efficiency. If you want to know more about that, let me know.
public View getView(int position, View convertView, ViewGroup parent) {
tempDeal = exampleBoxArrayList.get(position);
ViewHolder holder;
if (convertView == null) {
convertView = inflator.inflate(R.layout.list_item_example_box, null);
holder = new ViewHolder();
holder.divider = (RelativeLayout) convertView.findViewById(R.id.example_box_divider);
holder.merchantName = (TextView) convertView.findViewById(R.id.example_box_merchant_name);
holder.expireDate = (TextView) convertView.findViewById(R.id.example_box_expire_date);
holder.description = (TextView) convertView.findViewById(R.id.example_box_description);
convertView.setTag(holder);
} else {
holder = (ViewHolder) convertView.getTag();
}
if (tempDeal.isDivider()) {
holder.divider.setVisibility(View.VISIBLE);
} else {
holder.divider.setVisibility(View.GONE);
}
holder.merchantName.setText(tempDeal.getMerchantName());
holder.expireDate.setText(tempDeal.getExpiryDateString());
holder.description.setText(tempDeal.getPriceOption().getDescription());
return convertView;
}
As you can see, I call the isDivider() method on my custom object (this method looks at a boolean set on data load). This method is used to turn the visibility of part of the layout on or off.
Alternatively, you could load a completely new layout based on this same concept.
I have an activity with multiple list views that are continuously receiving new values form a socket thread, another thread parses the data and updates the array adapters, then the ui thread calls notifyDataSetChanged() to cause the list to refresh.
My issue is that im refreshing all the list a couple of time a second, this causes the UI to be very laggy when some animations need to happen.
I was wondering what the best way is to update multiple lists with multiple value changes every second?
Thanks,
Totem.
I would definately follow the guidelines they gave at Google IO this year.
Google IO listview Video
You should use Cursors (if required Content Providers) and ListActivity. The UI automatically updates as soon as there are changes and in case of null data sets, the list automatically displays a relevant view.
Following examples solves it using content providers:
main.xml:
<ListView android:id="#id/android:list" android:layout_width="fill_parent"
android:layout_height="wrap_content"></ListView>
<TextView android:id="#id/android:empty" android:layout_width="fill_parent"
android:gravity="center" android:layout_height="wrap_content"
android:text="No data, please refresh!" />
Notice the android:list and android:empty tags. These are required by the list activity.
In onCreate() method:
mCursor = getContentResolver().query(SOME_URI,
null, null, null, null);
ListView mListView = (ListView) findViewById(android.R.id.list);
mListView.setAdapter(new CustomCusorAdapter(getApplicationContext(),
mCursor));
You can use a SimpleCursorAdapter if your views are straight-forward. I created by own adapter because of the complex views:
private class CustomCusorAdapter extends CursorAdapter {
public CustomCusorAdapter(Context context, Cursor c) {
super(context, c);
}
#Override
public void bindView(View view, Context context, Cursor cursor) {
Holder holder = (Holder) view.getTag();
holder.tv.setText(cursor.getString(cursor
.getColumnIndex(COL1_NAME)));
}
#Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
View v = getLayoutInflater().inflate(
R.layout.layout_xml, null);
Holder holder = new Holder();
holder.tv = (TextView) v
.findViewById(R.id.tv);
holder.cb= (CheckBox) v
.findViewById(R.id.cb);
v.setTag(holder);
return v;
}
}
private class Holder {
TextView tv;
CheckBox cb;
}
Yes, that video is very helpful. One of the biggest take aways is that you should recycle the convertView passed into your list adapters getView method:
public View getView(int position, View convertView, ViewGroup parent){
if (convertView == null) {
convertView = mInflator.inflate(resource, parent, false);
}
//do any view bindings for the row
return convertView;
}
The other helpful bit was to use a ViewHolder class for the view recycling. It's at ~10:30 into the vid.