Skip to content

Instantly share code, notes, and snippets.

@JakeWharton
Last active July 25, 2023 05:49
Show Gist options
  • Star 107 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save JakeWharton/5423616 to your computer and use it in GitHub Desktop.
Save JakeWharton/5423616 to your computer and use it in GitHub Desktop.
An adapter base class that uses a new/bind pattern for its views.
// Apache 2.0 licensed.
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
/** An implementation of {@link BaseAdapter} which uses the new/bind pattern for its views. */
public abstract class BindableAdapter<T> extends BaseAdapter {
private final Context context;
private final LayoutInflater inflater;
public BindableAdapter(Context context) {
this.context = context;
this.inflater = LayoutInflater.from(context);
}
public Context getContext() {
return context;
}
@Override public abstract T getItem(int position);
@Override public final View getView(int position, View view, ViewGroup container) {
if (view == null) {
view = newView(inflater, position, container);
if (view == null) {
throw new IllegalStateException("newView result must not be null.");
}
}
bindView(getItem(position), position, view);
return view;
}
/** Create a new instance of a view for the specified position. */
public abstract View newView(LayoutInflater inflater, int position, ViewGroup container);
/** Bind the data for the specified {@code position} to the view. */
public abstract void bindView(T item, int position, View view);
@Override public final View getDropDownView(int position, View view, ViewGroup container) {
if (view == null) {
view = newDropDownView(inflater, position, container);
if (view == null) {
throw new IllegalStateException("newDropDownView result must not be null.");
}
}
bindDropDownView(getItem(position), position, view);
return view;
}
/** Create a new instance of a drop-down view for the specified position. */
public View newDropDownView(LayoutInflater inflater, int position, ViewGroup container) {
return newView(inflater, position, container);
}
/** Bind the data for the specified {@code position} to the drop-down view. */
public void bindDropDownView(T item, int position, View view) {
bindView(item, position, view);
}
}
@imminent
Copy link

I like to name convertView as reusableView, since that states it purpose a little clearer to me (think that comes from iOS TableView)

@ManuelPeinado
Copy link

For the common scenario where there is a single view type the following is slightly more convenient:
https://gist.github.com/ManuelPeinado/5424997

@JakeWharton
Copy link
Author

@ManuelPeinado Just ignore the type argument if you only have one view type.

@AlexBonel
Copy link

Take the 50th star :) I've never understood how does the presence of reference to a context in the adapter not make a leak of memory.

@imminent
Copy link

@AlexBonel A leak implies that it exists outside of the scope of its intended existence. The component that owns the BaseAdapter should be the Context (or owned by something that is the Context, a Fragment for example). In which case, the BaseAdapter can never have the Context when the Context is not to be had anymore, specifically because the BaseAdapter won't exist by that time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment