Adapters and lists - WonderCsabo/androidannotations GitHub Wiki
This is just a simple demonstration of how you could handle Adapters
and AdapterViews
in a simple way with AndroidAnnotations.
Let's say you have a Person
class:
public class Person {
public final String firstName;
public final String lastName;
public Person(String firstName, String lastName) {
this.firstName = firstName;
this.lastName = lastName;
}
}
and a PersonFinder
interface:
public interface PersonFinder {
List<Person> findAll();
}
We want to create a PersonListActivity
that lists all the available persons. For that, we'll need a PersonListAdapter
that binds the data to the views, and a PersonItemView
that is the view for one item in the list.
The PersonItemView
will use one TextView
for the first name, and one TextView
for the last name:
@EViewGroup(R.layout.person_item)
public class PersonItemView extends LinearLayout {
@ViewById
TextView firstNameView;
@ViewById
TextView lastNameView;
public PersonItemView(Context context) {
super(context);
}
public void bind(Person person) {
firstNameView.setText(person.firstName);
lastNameView.setText(person.lastName);
}
}
Notice that creating a custom view group that has its child views injected removes the need to use a View Holder Pattern.
There's a PersonFinder
implementation, let's say InMemoryPersonFinder
, that is annotated with @EBean
. We won't describe this implementation.
The adapter directly manipulates it to bind its data and create the corresponding views:
@EBean
public class PersonListAdapter extends BaseAdapter {
List<Person> persons;
@Bean(InMemoryPersonFinder.class)
PersonFinder personFinder;
@RootContext
Context context;
@AfterInject
void initAdapter() {
persons = personFinder.findAll();
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
PersonItemView personItemView;
if (convertView == null) {
personItemView = PersonItemView_.build(context);
} else {
personItemView = (PersonItemView) convertView;
}
personItemView.bind(getItem(position));
return personItemView;
}
@Override
public int getCount() {
return persons.size();
}
@Override
public Person getItem(int position) {
return persons.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
}
The PersonListActivity
binds the PersonListAdapter
to a ListView
, and displays a toast when a PersonItemView
is clicked.
@EActivity(R.layout.person_list)
public class PersonListActivity extends Activity {
@ViewById
ListView personList;
@Bean
PersonListAdapter adapter;
@AfterViews
void bindAdapter() {
personList.setAdapter(adapter);
}
@ItemClick
void personListItemClicked(Person person) {
makeText(this, person.firstName + " " + person.lastName, LENGTH_SHORT).show();
}
}
If you are using RecyclerView
instead of a simple ListView
, you should treat the situation a little bit differently. RecyclerView.Adapter
creates ViewHolder
s, instead of View
s. Unfortunately you cannot enhance and inject into ViewHolder
classes, but you can easily use @EViewGroup
as for ListView
s with a help of a modified adapter.
Create a generic class which can be used to wrap all kind of View
s into a ViewHolder
:
public class ViewWrapper<V extends View> extends RecyclerView.ViewHolder {
private V view;
public ViewWrapper(V itemView) {
super(itemView);
view = itemView;
}
public V getView() {
return view;
}
}
Create a common base class for all RecyclerView
adapters:
public abstract class RecyclerViewAdapterBase<T, V extends View> extends RecyclerView.Adapter<ViewWrapper<V>> {
protected List<T> items = new ArrayList<T>();
@Override
public int getItemCount() {
return items.size();
}
@Override
public final ViewWrapper<V> onCreateViewHolder(ViewGroup parent, int viewType) {
return new ViewWrapper<V>(onCreateItemView(parent, viewType));
}
protected abstract V onCreateItemView(ViewGroup parent, int viewType);
// additional methods to manipulate the items
}
You can utilize the two classes with our Person
example as follows:
@EBean
public class PersonAdapter extends RecyclerViewAdapterBase<Person, PersonItemView> {
@RootContext
Context context;
@Override
protected PersonItemView onCreateItemView(ViewGroup parent, int viewType) {
return PersonItemView_.build(context);
}
@Override
public void onBindViewHolder(ViewWrapper<PersonItemView> viewHolder, int position) {
PersonItemView view = viewHolder.getView();
Person person = items.get(position);
view.bind(person);
}
}
If you create an interface for the bind
method, you can even move up the implementation of onBindViewHolder
to the base class.