Mastering Android MVP: Build Decoupled, Leak‑Free Apps
This article explains how to use the Model‑View‑Presenter (MVP) pattern in Android to reduce module coupling, prevent memory leaks with WeakReference, and organize code into clear layers—View, Presenter, Model, and a Data Manager—while providing step‑by‑step implementations and reusable base classes.
Overview
Model‑View‑Presenter (MVP) separates an Android UI into three layers: View, Presenter and Model. The View never accesses the Model directly; all communication goes through the Presenter, which holds references to both. This decoupling enables independent evolution of UI and business logic.
Component Interfaces
IView
Defines UI callbacks that the Presenter can invoke.
public interface IView {
void showBook(BookBean bean);
}IModel
Defines data‑access operations and a nested callback interface used by the Presenter.
public interface IModel {
interface BookListener {
void onFinish(BookBean bean);
}
void getBook(BookListener listener);
void setBook(BookBean bean);
}Data Bean
public class BookBean {
private String bookContent;
public String getBookContent() { return bookContent; }
public void setBookContent(String bookContent) { this.bookContent = bookContent; }
}Concrete Model
Implements IModel. Data fetching is performed on a background thread and the result is delivered via the BookListener.
public class ModelImpl implements IModel {
private BookBean mBookBean;
@Override
public void getBook(final BookListener listener) {
new Thread(() -> {
// Simulate data retrieval
listener.onFinish(mBookBean);
}).start();
}
@Override
public void setBook(BookBean bean) {
mBookBean = bean;
}
}Presenter
Holds a weak reference to the View to avoid memory leaks and a strong reference to the Model. It forwards UI requests to the Model and returns results to the View.
public class Presenter implements IModel.BookListener {
private IView mView;
private IModel mModel;
public Presenter(WeakReference<IView> weakView) {
this.mView = weakView.get();
this.mModel = new ModelImpl();
}
public void getBook() {
mModel.getBook(this);
}
@Override
public void onFinish(BookBean bean) {
if (mView != null) {
mView.showBook(bean);
}
}
}Activity as View
The Activity implements IView, creates a weak reference to itself, and passes it to the Presenter.
public class BookActivity extends Activity implements IView {
private BookBean mBookBean;
private Presenter mPresenter;
private WeakReference<IView> mWeakReference;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mWeakReference = new WeakReference<>((IView) this);
mPresenter = new Presenter(mWeakReference);
mPresenter.getBook();
}
@Override
public void showBook(BookBean bean) {
mBookBean = bean;
// update UI here
}
}BasePresenter for Lifecycle Management
A generic abstract class that stores a WeakReference<T> to the View and provides attach/detach helpers.
public abstract class BasePresenter<T> {
protected WeakReference<T> mWeakView;
public void attachWeakView(T view) {
mWeakView = new WeakReference<>(view);
}
public T getWeakView() {
return mWeakView != null ? mWeakView.get() : null;
}
public boolean isWeakViewAttached() {
return mWeakView != null && mWeakView.get() != null;
}
public void detachWeakView() {
if (mWeakView != null) {
mWeakView.clear();
mWeakView = null;
}
}
}BaseViewGroup for Multiple Presenters
When a View (e.g., a custom ViewGroup) needs several Presenters, a base class can manage a list of presenters and bind/unbind them automatically.
public abstract class BaseViewGroup<V, T extends BasePresenter<V>> extends RelativeLayout {
protected List<T> mPresenterList;
protected abstract List<T> createPresenterList();
public BaseViewGroup(Context ctx, AttributeSet attrs, int defStyle) {
super(ctx, attrs, defStyle);
createPresenter();
}
private void createPresenter() {
mPresenterList = createPresenterList();
if (mPresenterList != null) {
for (BasePresenter presenter : mPresenterList) {
presenter.attachWeakView((V) this);
}
}
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
if (mPresenterList != null) {
for (BasePresenter presenter : mPresenterList) {
presenter.detachWeakView();
}
}
}
}BaseAdapter for RecyclerView
Similar to BaseViewGroup, it binds presenters when the adapter is attached to a RecyclerView and releases them on detach.
public abstract class BaseAdapter<V, T extends BasePresenter<V>>
extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
protected List<T> mPresenterList;
protected abstract List<T> createPresenterList();
@Override
public void onAttachedToRecyclerView(RecyclerView rv) {
super.onAttachedToRecyclerView(rv);
mPresenterList = createPresenterList();
if (mPresenterList != null) {
for (BasePresenter presenter : mPresenterList) {
presenter.attachWeakView((V) this);
}
}
}
@Override
public void onDetachedFromRecyclerView(RecyclerView rv) {
super.onDetachedFromRecyclerView(rv);
if (mPresenterList != null) {
for (BasePresenter presenter : mPresenterList) {
presenter.detachWeakView();
}
}
}
}Model‑Level DataManager
A manager layer can coordinate multiple data sources (memory cache, DB/file, network). The manager first checks an in‑memory cache, then falls back to a background DB/file access, and finally to a network request. Each request can be tagged with a unique key to avoid out‑of‑order responses.
Extended Architecture
In large projects a View may bind several Presenters and a Model may have multiple retrieval strategies. The diagram below (conceptual) shows two Views sharing two Presenters, and a Model that aggregates cache, database and network sources.
Summary
IView – UI contract for the Presenter.
IModel – Data contract with a callback interface.
Presenter – Mediates between View and Model, holds weak View reference.
BasePresenter – Provides generic weak‑reference handling and lifecycle hooks.
BaseViewGroup / BaseAdapter – Enable Views that host multiple Presenters to bind/unbind automatically.
DataManager – Centralizes data‑source selection and request tagging.
The core idea is to keep UI code independent from business logic, improve testability, and prevent memory leaks by using weak references and explicit lifecycle management.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
JD Retail Technology
Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
