In android development, a fragment
is a reusable piece of User Interface. It should contains no business logic and
(in the best scenario) should be usable by different apps.
Here are some thought about how this can be achieved.
Suppose we want to design a fragment able to display a list of Note
with their content, title, date of creation.
We want to open the NoteEditor
when a note is clicked, and we want to be able to delete one or more notes at once.
"Ok, I want to display the notes like this. I'm going to display their title in bold here, the creation date in small font there and an excerpt of their content here. I want checkboxes on the left, and I'm going to add two button at the bottom. Oh and I'm putting the search bar here to filter the list. etc."
- filtering the list doesn't need to be communicated to another class
- I need to fetch the list of notes with their {title, content, date of creation} that I'm displaying
- I need to tell the controler to delete some notes (those that are checked)
- I need to tell the controler to open a note (when it's clicked)
- I need to tell the controler to create a note (when the add button is clicked)
- data to receive: Items { title, summary, date }
- action: process checked items
- action: item clicked
- action: primary button clicked
class ListItem {
String title;
String summary;
Date date;
}
interface ListPresenterController {
void processItems(List<ListItem> items);
void primaryButtonClicked();
void itemClicked(ListItem item);
}
interface ListPresenter {
void receiveItems(List<ListItem> items, ListPresenterController c);
void setPrimaryButtonText(String text);
void setProcessButtonText(String text);
void displayFeedback(String feedback);
void onProcessItemsFailure(List<ListItem> unprocessed, String errorMessage);
void onProcessItemsSuccess(List<ListItem> processed);
void onItemClickedSuccess(ListItem item);
void onItemClickedFailure(ListItem item, String errorMessage);
void onPrimaryButtonClickedSuccess();
void onPrimaryButtonClickedFailure(String errorMessage);
}
class ListFragment extends Fragment implements ListPresenter { ... }
Now, do not use this fragment directly in your controller ! You want the controller to use an interface without
knowing if it's implemented by a ListPresenter
or something else.
Instead, design an interface to let the controler communicate clearly.
interface NotesPresenterController {
void deleteNotes(List<Note> toDelete);
void createNote();
void openNote(Note toOpen);
}
interface NotesPresenter {
void receiveNotes(List<Note> items);
void onDeleteNoteFailure(List<Note> notDeleted);
void onDeleteNoteSuccess(List<Note> deleted);
void onOpenNoteFailure(Note notOpened);
void onOpenNoteSuccess(Note opened);
void onCreateNoteFailure();
void onCreateNoteSuccess(Note created);
}
And implement it using an adapter:
class NotesPresenterFragmentAdapter implements NotesPresenter {
NotesPresenterFragmentAdapter(NotesPresenterController controller, ListFragment adapted) {
adapted.setPrimaryButtonText("Add");
adapted.setProcessButtonText("Deleted selected notes");
// etc.
}
void receiveNotes(List<Note> notes) {
List<ListItem> items = notes.map(...); // process the list of notes
adapted.receiveItems(items, this);
}
// etc.
}