Mobile Development 23 min read

From MVC to MVP to MVCPI: Android Architecture Practices and Performance Optimization

This article examines the evolution of Android UI architecture from traditional MVC to MVP and introduces the MVCPI extension, discussing practical implementation details, performance considerations, common pitfalls, and solutions such as interface-based views, presenter responsibilities, and interaction models to improve code maintainability and scalability.

Ctrip Technology
Ctrip Technology
Ctrip Technology
From MVC to MVP to MVCPI: Android Architecture Practices and Performance Optimization

Author Zhao Weilin, who has worked on Android development at Ctrip Hotel Business Department, shares his experience on component‑based architecture, system design, modeling, performance optimization, and code refactoring.

1. From MVC

The classic MVC pattern is widely used, but many developers complain that the Controller (often an Activity) becomes bloated when the UI grows.

<code>public class HotelActivity extends Activity {</code> <code> private TextView mNameView;</code> <code> private TextView mAddressView;</code> <code> private TextView mStarView;</code> <code> @Override</code> <code> protected void onCreate(Bundle savedInstanceState) {</code> <code> super.onCreate(savedInstanceState);</code> <code> setContentView(R.layout.activity_main2);</code> <code> mNameView = (TextView) findViewById(R.id.hotel_view);</code> <code> mAddressView = (TextView) findViewById(R.id.address_view);</code> <code> mStarView = (TextView) findViewById(R.id.star_view);</code> <code> HotelModel hotel = HotelLoader.loadHotelById(1000);</code> <code> mNameView.setText(hotel.hotelName);</code> <code> mAddressView.setText(hotel.hotelAdress);</code> <code> mStarView.setText(hotel.hotelStar);</code> <code> }</code> <code>}</code>

This code illustrates the basic MVC structure where the Activity plays the role of Controller, directly manipulating Views and Model data.

1.2 Proper MVC

In a more modular approach, the Activity delegates view handling to a dedicated view class, keeping the Controller thin.

<code>public class HotelActivity extends Activity {</code> <code> private HotelView mHotelView;</code> <code> @Override</code> <code> protected void onCreate(Bundle savedInstanceState) {</code> <code> super.onCreate(savedInstanceState);</code> <code> setContentView(R.layout.activity_main2);</code> <code> HotelModel hotel = HotelLoader.loadHotelById(1000);</code> <code> mHotelView = (HotelView) findViewById(R.id.hotel_view);</code> <code> mHotelView.setHotel(hotel);</code> <code> }</code> <code>}</code>

The View now encapsulates UI components, and the Controller only coordinates data flow.

2. Android MVP

Google’s official MVP reference separates responsibilities into three interfaces: IView, IPresenter, and a concrete Presenter implementation.

<code>public interface IHotelView {</code> <code> TextView getNameView();</code> <code> TextView getAddressView();</code> <code> TextView getStarView();</code> <code>}</code>
<code>public interface IHotelPresenter {</code> <code> void setView(IHotelView hotelView);</code> <code> void setData(HotelModel hotel);</code> <code>}</code>
<code>public class HotelPresenter implements IHotelPresenter {</code> <code> private IHotelView hotelView;</code> <code> @Override</code> <code> public void setView(IHotelView hotelView) {</code> <code> this.hotelView = hotelView;</code> <code> }</code> <code> @Override</code> <code> public void setData(HotelModel hotel) {</code> <code> hotelView.getNameView().setText(hotel.hotelName);</code> <code> hotelView.getAddressView().setText(hotel.hotelAddress);</code> <code> hotelView.getStarView().setText(hotel.hotelStar);</code> <code> }</code> <code>}</code>

The Activity implements IHotelView and forwards UI events to the Presenter. While this decouples View and Model, several practical problems appear:

Context loss when the Presenter needs to show a Toast or start an Activity.

Lifecycle mismatches leading to memory leaks.

Long callback chains when many UI actions require custom interfaces.

Example of a context‑related issue:

<code>public void setData(HotelModel hotelModel) {</code> <code> View button = mHotelView.getButtonView();</code> <code> if (hotelModel.showButton) {</code> <code> button.setOnClickListener(new View.OnClickListener() {</code> <code> @Override public void onClick(View v) { sendRequest(); }</code> <code> });</code> <code> }</code> <code>}</code> <code>private void sendRequest() {</code> <code> new Thread() { public void run() {</code> <code> // ... network call ...</code> <code> handler.post(new Runnable() { public void run() {</code> <code> Toast.makeText(???, "成功", Toast.LENGTH_SHORT).show(); // Context missing</code> <code> } });</code> <code> } }.start();</code> <code>}</code>

To solve these issues, the author experimented with passing a Fragment as context, adding lifecycle callbacks, and finally introducing a callback interface to let the Activity handle UI‑specific actions.

3. MVCPI – Extending MVC with MVP Concepts

The final solution, named MVCPI, adds three new concepts:

IView : a weak‑typed interface that only declares view IDs (e.g., NAME_VIEW, ADDRESS_VIEW), allowing any layout to satisfy the contract without the Activity implementing a large interface.

Presenter : responsible for binding data to the view and delegating business logic to a Controller; it receives a generic View and looks up child views using the IDs defined in IView.

Interactor : an interaction model that aggregates all UI event listeners (e.g., button clicks) in a single object, eliminating long callback chains and making the whole screen’s interaction graph explicit.

Key code snippets:

<code>public interface IView {</code> <code> int NAME_VIEW = R.id.name_view;</code> <code> int ADDRESS_VIEW = R.id.address_view;</code> <code> int STAR_VIEW = R.id.star_view;</code> <code> int DETAIL_BUTTON = R.id.detail_button;</code> <code>}</code>
<code>public class HotelPresenter {</code> <code> private View hotelView;</code> <code> private HotelInteractor interactor;</code> <code> private Button detailButton;</code> <code> public HotelPresenter(HotelInteractor interactor) { this.interactor = interactor; }</code> <code> public void setView(View view) {</code> <code> this.hotelView = view;</code> <code> detailButton = (Button) view.findViewById(IView.DETAIL_BUTTON);</code> <code> }</code> <code> public void setData(HotelModel hotel) {</code> <code> // bind model fields to UI</code> <code> if (hotel.showButton) {</code> <code> detailButton.setVisibility(View.VISIBLE);</code> <code> detailButton.setOnClickListener(interactor.mDetail);</code> <code> }</code> <code> }</code> <code>}</code>
<code>public class HotelInteractor {</code> <code> public View.OnClickListener mDetail;</code> <code>}</code>

The Activity now becomes a thin assembler:

<code>public class HotelActivity extends Activity {</code> <code> @Override protected void onCreate(Bundle savedInstanceState) {</code> <code> super.onCreate(savedInstanceState); setContentView(R.layout.activity_main2); HotelInteractor interactor = new HotelInteractor(); interactor.mDetail = new View.OnClickListener() { public void onClick(View v) { viewHotelDetail(); } }; HotelModel model = HotelLoader.loadHotelById(1000); HotelPresenter presenter = new HotelPresenter(interactor); presenter.setView(findViewById(R.id.hotel_view)); presenter.setData(model); } }</code>

By separating view IDs, interaction handling, and data binding, MVCPI achieves:

Clearer responsibilities – the Controller (Activity) only wires components.

Reduced boilerplate – no need for the Activity to implement a large view interface.

Better testability – Presenter and Interactor can be unit‑tested independently.

Fewer memory‑leak risks – no long‑lived references to Context inside Presenter.

Conclusion

The article concludes that MVC remains a robust foundation, MVP adds useful decoupling but introduces its own complexities, and the MVCPI extension combines the strengths of both while adding an explicit interaction model. In Ctrip’s large‑scale hotel project, MVCPI improved code simplicity, maintainability, and scalability, making it a valuable pattern for complex Android applications.

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.

performance optimizationAndroidMVCMVP
Ctrip Technology
Written by

Ctrip Technology

Official Ctrip Technology account, sharing and discussing growth.

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.