Mobile Development 23 min read

Understanding and Building an Android MVVM Application Framework

The article clarifies that Android MVVM is an architectural pattern distinct from Google’s DataBinding tool, contrasts MVC and MVP shortcomings, outlines MVVM’s View, Model, and ViewModel layers with detailed responsibilities and sample RxJava/Retrofit code, and recommends using a global Messenger for decoupled ViewModel communication to achieve low‑coupling, testable, data‑driven UI development.

Meituan Technology Team
Meituan Technology Team
Meituan Technology Team
Understanding and Building an Android MVVM Application Framework

When people mention Android MVVM, they often think of Google’s DataBinding framework released in 2015. However, the two concepts are different: MVVM is an architectural pattern, while DataBinding is a tool that implements data‑UI binding and can be used to construct an MVVM framework.

The article first explains the three classic Android UI patterns—MVC, MVP, and MVVM—highlighting the shortcomings of MVC (Activities become massive) and MVP (interface granularity, UI‑driven logic, and coupling). It then introduces MVVM, describing its three layers:

View : Activity/Fragment and XML, responsible only for UI rendering and user interaction.

Model : Data sources such as network APIs, local storage, and entity beans.

ViewModel : Handles business logic, holds ObservableFields, and communicates with View via DataBinding and with Model via RxJava/Retrofit.

Key advantages of MVVM are data‑driven UI updates, low coupling, easier UI testing, clear division of labor, and better team collaboration.

How to divide responsibilities:

View should contain no business logic; it only initializes UI components and declares bindings in XML. UI events are bound to commands defined in ViewModel.

ViewModel contains five typical parts:

Context – used mainly for lifecycle‑aware network requests and messenger registration.

Model – reference to the data objects (e.g., beans returned by Retrofit).

Data Fields – ObservableField/ObservableBoolean that are bound to UI widgets.

Command – ReplyCommand objects that encapsulate UI events such as refresh or load‑more.

Child ViewModel – ObservableList of sub‑ViewModels for RecyclerView adapters, fragments, etc.

Example code for these parts:

//context
private Activity context;
//model (data source Java Bean)
private NewsService.News news;
private TopNewsService.News topNews;
//data binding fields
public final ObservableField<String> imageUrl = new ObservableField<>();
public final ObservableField<String> html = new ObservableField<>();
public final ObservableField<String> title = new ObservableField<>();
public final ViewStyle viewStyle = new ViewStyle();
//command binding
public final ReplyCommand onRefreshCommand = new ReplyCommand(() -> {
    // refresh logic
});
public final ReplyCommand<Integer> onLoadMoreCommand = new ReplyCommand<>(itemCount -> {
    int page = itemCount / LIMIT + 1;
    loadData(page);
});
//child ViewModel list
public final ObservableList<NewItemViewModel> itemViewModel = new ObservableArrayList<>();

/**
 * ViewStyle – UI‑independent style properties
 */
public static class ViewStyle {
    public final ObservableBoolean isRefreshing = new ObservableBoolean(true);
    public final ObservableBoolean progressRefreshing = new ObservableBoolean(true);
}

The article also shows how ViewModel interacts with Model using RxJava and Retrofit, wrapping network calls into Observable streams and binding them to the Activity lifecycle:

//Model
private NewsDetail newsDetail;
private void loadData(long id) {
    Observable<Notification<NewsDetailService.NewsDetail>> newsDetailOb =
        RetrofitProvider.getInstance()
            .create(NewsDetailService.class)
            .getNewsDetail(id)
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .compose(((ActivityLifecycleProvider) context).bindToLifecycle())
            .materialize().share();
    newsDetailOb.filter(Notification::isOnNext)
        .map(n -> n.getValue())
        .doOnNext(m -> newsDetail = m)
        .subscribe(m -> initViewModelField(m));
    // error handling omitted for brevity
}

private void initViewModelField(NewsDetail newsDetail) {
    viewStyle.isRefreshing.set(false);
    imageUrl.set(newsDetail.getImage());
    Observable.just(newsDetail.getBody())
        .map(s -> s + "<style type=\"text/css\">" + newsDetail.getCssStr())
        .map(s -> s + "</style>")
        .subscribe(s -> html.set(s));
    title.set(newsDetail.getTitle());
}

For communication between multiple ViewModels, the article recommends using a global Messenger (event bus) to avoid tight coupling. Sample code registers, sends, and unregisters messages.

//Sending a message from a child ViewModel
Messenger.getDefault().send(news, TOKEN_TOP_NEWS_FINISH);

//Receiving the message in the main ViewModel
Messenger.getDefault().register(activity, NewsViewModel.TOKEN_TOP_NEWS_FINISH,
    TopNewsService.News.class, news -> { /* handle news */ });

@Override
protected void onDestroy() {
    super.onDestroy();
    Messenger.getDefault().unregister(this);
}

Finally, the article provides a summary and links to the source code (MVVM Light Toolkit on GitHub) and suggests combining this approach with Google’s open‑source MVP samples for unit testing.

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.

AndroidKotlinMVVMRxJavaDataBinding
Meituan Technology Team
Written by

Meituan Technology Team

Over 10,000 engineers powering China’s leading lifestyle services e‑commerce platform. Supporting hundreds of millions of consumers, millions of merchants across 2,000+ industries. This is the public channel for the tech teams behind Meituan, Dianping, Meituan Waimai, Meituan Select, and related services.

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.