Part of PatternKit, a side-by-side reference codebase where the same small Tasks CRUD app is implemented once per architecture pattern across iOS and Android. Every module ships identical behaviour — the same domain model, the same three screens, the same mock data layer — so the only thing that varies is the architecture itself.
This module is the MVP (Model–View–Presenter) flavour on the traditional XML view stack — MVP's natural Android home. It's a purist take: each Fragment is a passive view that implements a Contract.View interface, and the Presenter drives it through that interface. The Fragment forwards user actions to the presenter and renders whatever the presenter pushes; it holds no presentation logic.
Why purist? PatternKit already has MVVM, MVVM+Clean, and MVI modules. MVP is here as a faithful reference. Notice the classic Android MVP weakness it makes visible: the Presenter is a plain object (not a
ViewModel), so it doesn't survive a configuration change — the Fragment recreates it and the screen reloads on resume. That fragility is exactly whyViewModel/MVVM won on Android, and seeing it is the point. The Compose sibling (PatternKitAndroidMvpCompose) shows the same contract deliberately against the grain of a declarative UI.
- Language: Kotlin
- UI: XML layouts + ViewBinding · Fragments ·
RecyclerView - Architecture: MVP — passive Fragments behind Contract.View interfaces, presenters own all logic
- Async: the presenter owns a
CoroutineScope(cancelled ondetach) - Navigation: in the Fragments, on the presenter's command (Contract.View routing methods)
- DI: Dagger 2 (KSP) —
AppComponentexposes the repository; presenters are built per view lifecycle - Min SDK: 28 · Target/Compile SDK: 36
- Package:
com.preetanshumishra.patternkit.android.mvpxml
A single-user task list. One entity (TaskItem: title, optional notes, optional due date, priority, completion). Three screens: List (filter / sort / swipe-delete / add), Detail (toggle / edit / delete), Form (create or edit, validation, mock async save). Data comes from MockTaskRepository — an in-memory store seeded with ~12 tasks, configurable latency + failure rate.
- View (passive) — a Fragment implementing
…Contract.View. It exposesrender(state)/seed(…)/setSaveEnabled(…)/showError(…)and navigation commands (showDetail,showCreate,showEdit,close), forwards user actions to the presenter, and does nothing else. - Presenter — a plain class owning the presentation logic, the repository (plain MVP — no domain layer), and a
CoroutineScope. Holds the view via the Contract interface; navigation is a presenter decision the Fragment carries out. - Model —
TaskItem+ theTaskRepository, the shared source of truth; screens reload on resume so edits elsewhere are reflected.
app/src/main/
├── kotlin/.../mvpxml/
│ ├── data/ # MockTaskRepository, TaskRepository, seed data
│ ├── model/ # TaskItem, Priority, TaskFilter, TaskSort
│ ├── di/ # AppComponent, RepositoryModule
│ ├── presentation/ # TaskList/Detail/Form Contract + Presenter
│ ├── ui/
│ │ ├── list/ # TaskListFragment (passive) + TaskAdapter
│ │ ├── detail/ # TaskDetailFragment (passive)
│ │ ├── form/ # TaskFormFragment (passive)
│ │ ├── NavArgs.kt, MainActivity
│ └── PatternKitApp.kt
└── res/ # layouts, menus, nav_graph.xml
./gradlew assembleDebug # build the debug APK
./gradlew installDebug # install on a connected device/emulatorOr open the project in Android Studio and run the app configuration.