Mobile Development 14 min read

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.

JD Retail Technology
JD Retail Technology
JD Retail Technology
Mastering Android MVP: Build Decoupled, Leak‑Free Apps

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.

Extended MVP diagram
Extended MVP diagram

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.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

architectureAndroidMVPPresenterWeakReference
JD Retail Technology
Written by

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.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.