GetView Vs. BindView in a custom CursorAdapter?
CursorAdapter
has an implementation of getView()
that delegates to newView()
and bindView()
, in such a way as enforces the row recycling pattern. Hence, you do not need to do anything special with a CursorAdapter
for row recycling if you are overriding newView()
and bindView()
.
Android CursorAdapter getView / newView should be inflate same things?
Implementing getView()
or the newView()/bindView()
group is the same thing in terms of performance and you should choose the later option. For Cursor
based adapters the getView()
method is implemented so it uses the view recycling mechanism along with delegating the row construction to the newView()
(build the views of the row) and bindView()
(bind the data to the rows) methods. It also moves the Cursor
to the correct position.
Also, as njzk2 , pointed out you should set the data on the view in the bindView()
method. The newView()
method will not be called for every row of the ListView
, it will be called only for the case when there isn't a recycled row already available, that's why you should only build the row view in newView()
. The bindView()
method, however, will be called each time and here's where you should bind the data from the Cursor
to the row views.
What bindView() and newView() do in CursorAdapter
In order to understand this, you must first understand how BaseAdapter
works, since CursorAdapter
is a subclass of BaseAdapter
.
Android maintains a pool of views for a ListView
which it will give to you so you can reuse it instead of creating a new view each time.
In BaseAdapter
, you will have a function called getView()
, to which one of the parameters is a View
object named convertView
. Basically, this convertView
will be null
if the list is being loaded for the first time, and it will not be null
once you start sliding the list. Therefore, in the getView()
method of your BaseAdapter
, you will check if convertView
is null
. If yes, you will inflate it. Then you can use the view and set its elements as normal. This will improve the scrolling performance of a listview tremendously.
A CursorAdapter
makes it easy to use when the data source of a listview is a database. In a cursor adapter, however, Android takes care of checking whether the convertView
is null
or not. In the newView()
method, you simply inflate the view and return it. In the bindView()
method, you set the elements of your view.
As an example, imagine a listview on a device which can show upto 11 list items on the screen. In this case, newView()
will be called upto 11 times. However, bindView()
will be called many times whenever you scroll the list view. The 11 views you created in your newView method will be reused again and again as you scroll the list.
get a position in bindView using CursorAdapter
For This first you need to override getView()
and set the position here and access it in bindview()
later.
@Override
public View getView(int position, View convertview, ViewGroup arg2) {
if (convbertview == null) {
LayoutInflater inflater = LayoutInflater.from(context);
convertview = inflater.inflate(R.layout.your layout,
null);
}
convertview.setTag(position);
return super.getView(position, convbertview, arg2);
}
and in bindView()
get your position like
@Override
public void bindView(View view, Context context, Cursor cursor) {
int position=(Integer) view.getTag();//here is the position
}
ViewHolder pattern correctly implemented in custom CursorAdapter?
CursorAdapter
won't call the newView
each time it needs a new row; if it already has a View
, it will call the bindView
, so the created view is actually reused.
That said, as pointed out by Joseph in the comments, you can still use ViewHolder in order to avoid calling findViewById
repeatedly.
If you are still concerned about efficiency then take a look at the SimpleCursorAdapter
implementation, which uses a WeakHashMap
(a map of WeakReferences
):
WeakHashMap<View, View[]> mHolders = new WeakHashMap<View, View[]>();
CursorAdapter inconsistent between newView and bindView
By default, ListView
(and any other source that takes a CursorAdapter
tries to reuse views as often as possible.
Therefore newView()
is called only until enough views are created and after that, only bindView()
is called as you scroll down the list as it reuses the views it has already created.
If you have multiple view types (as it seems you do), you should also override getViewTypeCount() and getItemViewType(). These methods tell the adapter that only views of the same type should be reused, ensuring that your rows using listrow_chat_me
are only used for future listrow_chat_me
rows and not reused for listrow_chat_other
rows.
@Override
public int getViewTypeCount() {
return 2;
}
@Override
public int getItemViewType(int position) {
// getItem(position) returns a Cursor at the given position
Cursor cursor = (Cursor) getItem(position);
if (cursor.getInt(cursor.getColumnIndexOrThrow(DbChat.KEY_SENDER_ID)) == 0) {
return 0;
} else {
return 1;
}
}
Issues with a ListView and a custom cursorAdapter
you have not return view from getView() method. current you return null value .that's why you get null pointer exception call newview inside getView() and return appropriate view .
for more info read below SO Question
What bindView() and newView() do in CursorAdapter
Android: Issue with newView and bindView in custom SimpleCursorAdapter
Overriding the getView()
function gives you the possibility of "re-using" already inflated list items (the list items that are "scrolled out" from the current view port when you scroll your list back and forth).
By doing so you'll save a lot of memory resources and processor run time, since inflating is a quite time consuming operation. For each and every convertView
you re-use you also save GC run-time (since the garbage collector doesn't have to collect that specific list item).
You can also create a "view collection" class (the ViewHolder
class in the below example) which will hold the references for each view in your inflated list item. This way you don't have to find them each and every time you update a list item with new values (typically whan you scroll the list). findViewById()
is also a rather time consuming operation.
Also I think you can cache more variables, like the layout inflater, and the column indices. Everything to save time :-)
private final Context mContext;
private final int mLayout;
private final Cursor mCursor;
private final int mNameIndex;
private final int mIdIndex;
private final LayoutInflater mLayoutInflater;
private final class ViewHolder {
public TextView name;
public ImageView image;
public CheckBox checkBox;
}
public FriendAdapter(Context context, int layout, Cursor c, String[] from, int[] to) {
super(context, layout, c, from, to);
this.mContext = context;
this.mLayout = layout;
this.mCursor = c;
this.mNameIndex = mCursor.getColumnIndex(WhipemDBAdapter.KEY_NAME);
this.mIdIndex = mCursor.getColumnIndex(WhipemDBAdapter.KEY_FB_ID);
this.mLayoutInflater = LayoutInflater.from(mContext);
}
public View getView(int position, View convertView, ViewGroup parent) {
if (mCursor.moveToPosition(position)) {
ViewHolder viewHolder;
if (convertView == null) {
convertView = mLayoutInflater.inflate(mLayout, null);
viewHolder = new ViewHolder();
viewHolder.name = (TextView) convertView.findViewById(R.id.contact_name);
viewHolder.image = (ImageView) convertView.findViewById(R.id.contact_pic);
viewHolder.checkBox = (CheckBox) convertView.findViewById(R.id.checkbox);
convertView.setTag(viewHolder);
}
else {
viewHolder = (ViewHolder) convertView.getTag();
}
String name = mCursor.getString(mNameIndex);
String fb_id = mCursor.getString(mIdIndex);
Drawable drawable = LoadImageFromWebOperations("http://graph.facebook.com/"+fb_id+"/picture");
boolean isChecked = ((GlobalVars) mContext.getApplicationContext()).isFriendSelected(fb_id);
viewHolder.name.setText(name);
viewHolder.image.setImageDrawable(drawable);
viewHolder.checkBox.setTag(fb_id);
viewHolder.checkBox.setChecked(isChecked);
}
return convertView;
}
Android - How to get position in bindView like in getView?
Try this
public void bindView(View arg0, Context arg1, Cursor arg2)
{
int pos = arg2.getPosition();
}
Related Topics
How to Use Okhttp to Upload a File
How to Know Whether I am in a Call on Android
What's a Good Library for Parsing Mathematical Expressions in Java
Android How to Listen for Volume Button Events
Android: Switch Camera When Button Clicked
How to Change a Bitmap's Opacity
What Is Difference Between @+Id/Android:List and @+Id/List
Send Sms Until It Is Successful
Change Listview Background - Strange Behaviour
Code Will Only Return 0.0, 0.0 Gps Coordinate While Throwing Nullpointerexception
Android Studio Convert Iso String to "America/New_York" When Adding to Event to Calendar
How to Save Image File in Android Oreo Update. How to Do It
How to Parse This JSON in Android
Android: Realm + Retrofit 2 + Gson
Navigation Drawer Closes on Click