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 ViewHolders, instead of Views. Unfortunately you cannot enhance and inject into ViewHolder classes, but you can easily use @EViewGroup as for ListViews with a help of a modified adapter.
Create a generic class which can be used to wrap all kind of Views 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.