Adapter Views - nhaarman/Triad GitHub Wiki

Triad makes dealing with AdapterViews such as ListView a bliss. Each item in the ListView is backed by a single Presenter. This simplifies state management a lot, and helps you keep your code cleaner as well.

Example

Let's say we want to show a list of notes in a NotesContainer. Our NotesPresenter will fetch the notes from a repository, wrap them in Presenters, and forward them to the Container:

class NotesPresenter extends Presenter<NotesContainer, ActivityComponent> {

  /**
   * Provides storage for our notes.
   */
  @NonNull
  private final NotesRepository mNotesRepository;

  @Nullable
  private List<NotePresenter> mNotePresenters;

  NotesPresenter(@NonNull final NotesRepository notesRepository) {
    mNotesRepository = notesRepository;
  }

  @Override
  public void onControlGained(@NonNull final NotesContainer container, @NonNull final ActivityComponent activityComponent) {
    if (mNotePresenters == null) {
      List<Note> notes = mNotesRepository.getNotes();
 
      mNotePresenters = new ArrayList<>(notes.size());
      for (Note note : notes) {
        mNotePresenters.add(new NotePresenter(note));
      }
    }

    container.setNotes(mNotePresenters);
  }
}

Our Container extends ListViewContainer, and manages the ListAdapter:

public class NotesView extends ListViewContainer<NotesPresenter, ActivityComponent> implements NotesContainer {

  @NonNull
  private final NotesAdapter mAdapter;

  @Nullable
  private List<NotePresenter> mNotes;

  public NotesView(final Context context, final AttributeSet attrs, final int defStyle) {
    super(context, attrs, defStyle, NotesListPresenter.class);
    mAdapter = new NotesAdapter();
  }

  @Override
  public void onFinishInflate() {
    super.onFinishInflate();

    setAdapter(mAdapter);
  }

  @Override
  public void setNotes(@NonNull final List<NotePresenter> notes) {
    mNotes = notes;
    mAdapter.notifyDataSetChanged();
  }

  private class NotesAdapter extends BaseAdapter {
  
    @Override
    public int getCount() {
      return mNotes == null ? 0 : mNotes.size();
    }

    @Override
    public NotePresenter getItem(final int position) {
      return mNotes == null ? null : mNotes.get(position);
    }

    @Override
    public long getItemId(final int position) {
      return position;
    }

    @Override
    public View getView(final int position, final View convertView, final ViewGroup parent) {
      NoteContainer view = (NoteContainer) convertView;
      if (view == null) {
        view = (NoteContainer) LayoutInflater.from(getContext()).inflate(R.layout.view_note, parent, false);
      }

      view.setPresenter(getItem(position));

      return (View) view;
    }
  }
}

The only thing left to do is to fill the NoteContainer when the NotePresenter gains control over it:

class NotePresenter extends Presenter<NoteContainer, ActivityComponent> {

  @NonNull
  private final Note mNote;

  NotePresenter(@NonNull final Note note) {
    mNote = note;
  }

  @Override
  public void onControlGained(@NonNull final NoteContainer container, @NonNull final ActivityComponent activityComponent) {
    container.setTitle(mNote.getTitle());
    container.setContents(mNote.getContents());
  }
}

Implementing ListViews this way makes for clean, modular and highly testable code.

⚠️ **GitHub.com Fallback** ⚠️