MVC Architectural Pattern in Android – Part 3

This is the third post in the series about Model View Controller (MVC) architectural pattern in context of Android development (part 1, part 2).

In the previous post I showed you how to extract UI logic into standalone MVC view class and “hide” the implementation details behind an interface. In this article you’ll learn how to implement MVC controllers.

MVC Controller

Each application has its own “flow” which is achieved by careful definition of specific rules by developers. These rules include (but are not limited to) the following aspects:

  • which state should be rendered on UI
  • how to handle user interactions with the UI
  • how to handle device state changes (connectivity, location, orientation, etc.)

The above set of rules, when captured in code, constitutes application’s “application” logic (I know it sounds a bit weird, but that’s the term). In MVC, controllers are the components that encapsulate this type of logic.

It’s also important to note that the above set of rules does not include the functionalities of MVC views and MVC models. So, the way your app renders UI and the way it manages domain state are not part of controller’s responsibilities.

MVC Controller Implementation

As we discussed in part 1 of this series, Activities and Fragments are the best candidates to become MVC controllers. If you still feel uncomfortable with this statement, you can read my previous article that explains why Activities in Android are not UI elements.

The general idea is that MVC controller takes care of user’s “flow” within the application. It decides which data to render on the UI and which actions to execute in response to user interactions. Each controller is associated with one or more MVC views, to which it delegates UI rendering. Controllers also interact with MVC model in order to query or update application’s domain state.

As an example, let’s review the implementation of SmsDetailsFragment from the tutorial application:

public class SmsDetailsFragment extends BaseFragment implements
        SmsDetailsViewMvc.Listener,
        MarkSmsAsReadUseCase.Listener,
        FetchSmsByIdUseCase.Listener {

    private static final String ARG_SMS_MESSAGE_ID = "arg_sms_message_id";

    public static Fragment newInstance(long smsId) {
        Bundle args = new Bundle(1);
        args.putLong(SmsDetailsFragment.ARG_SMS_MESSAGE_ID, smsId);
        Fragment fragment = new SmsDetailsFragment();
        fragment.setArguments(args);
        return fragment;
    }

    private ViewMvcFactory mViewMvcFactory;
    private ScreensNavigator mScreensNavigator;
    private FetchSmsByIdUseCase mFetchSmsByIdUseCase;
    private MarkSmsAsReadUseCase mMarkMessageAsReadUseCase;
    private DefaultSmsAppTester mDefaultSmsAppTester;

    private SmsDetailsViewMvc mViewMVC;

    private long mSmsId;

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mFetchSmsByIdUseCase = getCompositionRoot().getFetchSmsByIdUseCase();
        mViewMvcFactory = getCompositionRoot().getViewMvcFactory();
        mScreensNavigator = getCompositionRoot().getScreenNavigator();
        mMarkMessageAsReadUseCase = getCompositionRoot().getMarkSmsAsReadUseCase();
        mDefaultSmsAppTester = getCompositionRoot().getDefaultSmsAppTester();

        mSmsId = getArguments().getLong(ARG_SMS_MESSAGE_ID);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

        mViewMVC = mViewMvcFactory.newSmsDetailsViewMvc(container);

        /*
        Starting with API 19 (KitKat), only applications designated as default SMS applications
        can alter SMS attributes (though they still can read SMSs). Therefore, on post KitKat
        versions "mark as read" button is only relevant if this app is the default SMS app.
         */
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            if (!mDefaultSmsAppTester.isDefaultSmsApp()) {
                mViewMVC.hideMarkAsReadButton();
            }
        }

        return mViewMVC.getRootView();
    }

    @Override
    public void onStart() {
        super.onStart();
        mViewMVC.registerListener(this);
        mFetchSmsByIdUseCase.registerListener(this);
        mMarkMessageAsReadUseCase.registerListener(this);

        mFetchSmsByIdUseCase.fetchSmsById(mSmsId);
    }

    @Override
    public void onStop() {
        super.onStop();
        mViewMVC.unregisterListener(this);
        mFetchSmsByIdUseCase.unregisterListener(this);
        mMarkMessageAsReadUseCase.unregisterListener(this);
    }


    @Override
    public void onSmsFetched(SmsMessage sms) {
        mViewMVC.bindSmsMessage(sms);
    }

    @Override
    public void onSmsFetchFailed(long smsId) {
        Toast.makeText(getActivity(), "Couldn't fetch the SMS message of interest!", Toast.LENGTH_LONG).show();
    }

    @Override
    public void onNavigateUpClicked() {
        mScreensNavigator.navigateBack();
    }

    @Override
    public void onMarkAsReadClicked() {
        mMarkMessageAsReadUseCase.markSmsAsRead(mSmsId);
    }

    @Override
    public void onSmsMarkedAsRead(long smsId) {
        if (smsId == mSmsId) {
            mFetchSmsByIdUseCase.fetchSmsById(mSmsId);
        }
    }
}

The main functionality of this controller is the following:

  1. Fetch data of a specific SMS message from the model
  2. Bind the fetched data to MVC view
  3. Control whether “mark as read” button should be dispalyed in the UI
  4. Delegate marking SMS message as “read” to the model upon receiving notification about user interaction from MVC view

It’s also important to note which logic this controller doesn’t contain:

  1. MVC controller does not contain UI implementation details (i.e. no dependency on Android View class, no references to R.id.* identifiers, etc.). Therefore, you can introduce completely different implementation of SmsDetailsViewMvc and switch to this new implementation by changing just one line of code inside ViewMvcFactory class (that’s so-called Open-Closed Principle in action).
  2. MVC controller does not contain implementation details of domain logic. It delegates all domain functionality (related to SMS in this case) to “use case” classes, which constitute the model.

In terms of “dirtiness metrics” defined in Activities in Android are not UI elements post, the above implementation of controller scores 0 “dirtiness points”.

Standalone Unit-Testable Controller

The implementation of MVC controllers inside Activities and Fragments is convenient and aligns well with the fundamental architecture of Android platform itself. However, it’s not unit testable.

Therefore, if you’d like to unit test controllers’ logic, you’ll need to extract that logic into standalone controller class. However, keep in mind that Activities and Fragments will still remain integral parts of your controller implemenation. Just like MVC views and MVC models, which can require more than one class to be implemented, MVC controllers can also be composite components. In fact, MVC controllers can even be nested, but that’s an advanced use case which I won’t discuss here.

MVC Model

Up until now in this series I explained how you can implement MVC views and MVC controllers. What about MVC model? I use “use case” classes (also known as “interactors”) to represent the model. This idea comes straight from “Clean Architecture” school of thought. You saw two such use cases in the implementaion of SmsDetailsFragment above.

However, it doesn’t mean that all domain logic goes into these objects. Use cases are just abstractions that controllers use to interact with the model. The actual implementation of the model can be as complex as your product requirements demand. It’s just that controllers shouldn’t be exposed to that complexity.

For example, in the case of the tutorial application for this series of posts, Android’s ContentProvider which stores information about SMS messages is also part of the model. However, the controller doesn’t know about that and just uses specific use case classes.

If you want to learn more about use cases and how to implement them, you can read this detailed article.

Conclusion

In this series of posts I presented the best MVC architectural pattern for Android applications. This pattern is best aligned with the core architecture of Android platform itself and allows you to build high-quality, maintainable Android applications.

While this series of posts is quite long, it’s still too short to capture all the details of Android architecture. Therefore, if you look for a robust architecture for your Android project, or just want to learn more about Android architecture and MVC in general, I recommend taking my course designed for professional developers. It’s the most complete and advanced resource about Android architecture out there.

By this point, I know about tens of projects that used MVC in production and achieved outstanding results. However, given the fact that tens of thousands of developers read this series of posts over the years and thousands of professionals completed my architecture course, I suspect that there are hundreds, or even thousands of production Android applications out there that use MVC.

As you might’ve noted, I originally wrote this series of posts in 2015. Back then, the topic of architecture had been largely neglected by the official Android documentation. However, I believe that MVC is as relevant today as it had been back then. In fact, it might even be more relevant because the officially promoted MVVM pattern seems to be very unfortunate and can lead to total mess (for example, you can watch this code review of Google’s Android Dev Summit app).

Therefore, when developers ask me: “what’s the best architecture for Android applications today?”, I answer: “MVC!”.

Thank you for reading. If you’ve got any comments or questions, you can leave them below.

39 thoughts on “MVC Architectural Pattern in Android – Part 3”

  1. I know it has been awhile since this was posted. However, I have a few questions if you are still around to answer them πŸ™‚ So! I just started using MVC for the first time, and I think I can say I really like it! But there are a few things I have no idea how to properly implement. Namely how to handle fragments properly, in my app, I have one view that is capable of displaying a grid of images passed from my Controller(the fragment class). I would like to add a navdrawer to the project, that navdrawer should change what images are loaded, but preferably not switch out the fragment. That pushes me to say I need to have a Controller interface that my fragment can implement, that way when you go to create the fragment you just keep an instance and you can call .setImageProvider() or whatever. But this gets messy very quickly! The question is, how should I handle things like nav drawers, that should be app-wide on most devices, and yet need to communicate with their child fragment(s).
    Apologies on such a long post, I hope this makes a little sense πŸ˜›

    Reply
    • Hello and thank you for your question.
      So, basically, you want to affect the contents of various Fragments in your app from NavDrawer, right? This can be further generalized to a question of communication between two independent MVC Controllers in the application (e.g. Fragment displayed in Toolbar and Fragment displayed as main content).
      I see at least two possible approaches:
      1) The scheme you described is actually very close to the officially recommended approach for communication between Fragments. However, I think your analysis is correct and this kind of code increases system’s inter-coupling and is not easy to maintain in the long run.
      2) The better approach (IMHO) is to make use of event bus – “master” MVC Controller posts “update” events to event bus when user interactions occur, whereas “slave” MVC Controller registers itself to event bus in onStart() (unregisters in onStop()) in order to receive these events. Please note that I intentionally say “MVC Controller” and not “Fragment” – both the “master” and the “slave” could be Activities or Fragments (or even Services, which are not part of MVC at all). All my projects use Green Robot’s EventBus, and I can’t recommend it highly enough.

      Reply
  2. Thank you so much for this! If it’s not a problem, could you please tell me how you MVCed the navigation drawer? I’m not sure what the right approach is for it.

    Reply
  3. Hi Vasiliy. Thanks to your project I have finally understand the concept of the MVC pattern. But I have a questions regarding the structure of your sample project and structuring the future projects. So. In your project you named one of its root packages the “screens” package what implies that this package contains screens visible to the user. Does in this context placing the “common” package in the “screens” package where it is only a host for other screens is appropriate or not?

    Beside, after opening your sample project I misunderstood the concept of the “common” package. I thought that it contains elements used by packages of other screens and de facto it is true. It contains base elements (BaseFragment and ViewMvc) used in other screen packages. But as I mentioned above it is also a host for other screens. So, should not the “common” package be renamed? Or at least elements (BaseFragment and ViewMvc) should not be moved into other package outside the “common” and “screens” packages?

    Reply
    • Hi Damian, and thanks for your question.
      What you’re asking about is not strictly related to MVC, but to the general organization of project’s source code. When I come to think about it now, this topic definitely deserves a post by its own. The below explanation is just a brief summary of my approach, but I think it will be enough for you because you got most of it by yourself already.
      Top level packages reflect application’s “purpose”. For any application of considerable size, most of top level packages will borrow their names from the “business/problem domain”. In case of MVC tutorial app, which is SMS reader, there is a top-level package named “sms”. This package contains SmsMessage and SmsMessagesManager classes. In addition, there is top-level package named “common”. This package contains classes and sub-packages that can be used by multiple other top-level packages (therefore “common”).
      Now, it could be very convenient to associate screens (which are view-controller pairs with related logic) with the aforementioned top level packages. In practice, however, one screen can depend on multiple top level packages. The tutorial app is very simple, but imagine that we add messages aggregation by contact. Then we would add “contacts” package and “smsall” screen would use both “sms” and “contacts” packages. Therefore, screens can’t be associated with existing top level packages. This is the reason we put them as sub-packages in a dedicated top-level package named “screens”. But different screens can share logic (e.g. base classes). I put this common logic related to screens into “common” sub-package of “screens” package.
      Let’s summarize. Top level packages reflect application’s “purpose”. Ideally, you should be able to understand what business/problem domain the application targets just by reading the names of the top level packages. In addition, there will be “common” and “screens” top level packages. Each application’s screen will be represented by a sub-package in “screens” top-level package. In addition, there will “common” sub-package in “screens” for logic that is shared between multiple screens. I hope this clarifies the structure a bit.
      * I updated the tutorial application in order to reflect the structure described above.

      Reply
      • Thanks for your quick replay and clarification. If you do not mind I would be grateful If you validate or not my understanding. Suppose, that your SMS Reader application provides a settings screen. And it allows to set different options of settings for contact and SMSs. According to your explanation. The “screens” top-level package should contain the “contactssettings” and “smssettings” sub-packages that will represent application’s screens. I know that the both of the settings screens must have their own controllers in their “controller” sub-packages of their packages. Moreover, the “controller” package in the “common” sub-package in the “screens” top-level package should contain a class (e.g SettingsActivity) that provides the same logic and it is also the host for “contactssettings” and “smssettings” screens as the MainActivity class for “smsall” and “smsdetails” screens. But I want the “contactssettings” and the “smssettings” screens logic to be separated because I want them to be managed as a separated android task or just by design. And the top-level package named “settings” (containing class providing interface to write/read application preferences) should be added to application’s project structure that will be used by “contactssettings” and the “smssettings” screens packages. Is my understanding correct?

        Reply
        • Your understanding is correct.
          Few additional points to consider in respect with your specific example:

          1) Decide whether “settings” is a first class functionality of the app. If it is, then additional top-level package is appropriate. If it isn’t, then I’d put “settings” package into “common” top-level package (and, in fact, this is exactly what I did in IDoCare app)

          2) If “contactssettings” and “smssettings” are similar in functionality, then it might be better to put them in a single sub-package inside “screens”. Then, SettingsActivity could reside in this package too. This way you’ll have all settings screens related functionality in a single package. Both approaches are good, though, therefore it is more a matter of preference.

          3) If you want settings screens to run as different tasks, then you’ll need a separate Activity for each of them. This is not exactly analogous to MainActivity and “sms” screens which are implemented using so called “single Activity” approach.

          4) If you have both Activities and Fragments in some sub-package of “screens”, you can split “controllers” package into “activities” and “fragments” packages for readability. This is, again, a matter of personal preference.

          Reply
  4. Thanks this great tutorial.

    I’m missing something, I don’t see exactly where we have to implement the model as we implement the Controler at the SmsDetailsFragment and the View at ViewMvc, SmsDetailsViewMcv and SmsDetailsViewMcvImpl.

    Is it SmsMessagesManager the model or it’s SmsDetailsViewMcvImpl?

    Reply
    • Hi,
      The state that is being dispalyed is in the database of SMS messages which is not part of this application at all. Therefore, the model in this case is external to the application and is being accessed via ContentProvider.

      Whether SmsMessagesManager is part of a model or a controller is kind of debatable. I prefer to see it as part of the controller because it does not have a state by itself. Some people find it conceptually easier to see it as part of the model. As I said in the article, it doesn’t really matter – as long as this component is there and provides the required level of abstraction and encapsulation, call it whatever you like.

      Reply
  5. Hi, I have question regarding the ViewPager. In RootViewMvcImpl I inflate rootView from layout where the ViewPager is container for framgents. Is it correct to set OnPageChnageListener on the instance of viewPager and notifying the controller (Activity) about the currently displayed fragment through the listener provided by the RootViewMvc? And what about the adapter for ViewPager. Should it be set in RootViewImpl? I think not. I think RootViewImpl should provide method for controller to set FragmentStatePageAdapter on ViewPager.
    Is my understanding correct? Are other ways to implement ViewPager correctly in the context of MVC?

    Reply
    • Hello Damian,
      As you discovered, ViewPager for Fragments is going to be a bit dirty. Let me share a few thoughts on this subject from my own experience:

      1)
      Do you really need to use Fragments? IMHO, there are two uses cases for ViewPager with Fragments: a) each page represents independent and rich functionality (e.g. page1 is home, page2 is search, page3 is favorites, etc.) b) memory considerations require usage of FragmentStatePagerAdapter.
      In practice, however, many ViewPager’s don’t really need to work with Fragments and can work with MVC views (or even Android Views).

      2)
      If you use ViewPager with Fragments, there is no need to notify the host Activity about which Fragment is being shown. Fragments are self-sufficient, and if communication with host Activity is required – you can take care of it inside page Fragments themselves. If you think that there is a need in your case, it is an indication that you probably don’t need Fragments and MVC views will suffice.

      3)
      For the implementation of Fragment based ViewPager I suggest the following: have a separate Fragment that hosts only the ViewPager. Lets call it PagerHostFragment. Instead of using MVC, PagerHostFragment uses the old “spaghetti” approach. Put all the logic that manages page Fragments inside PagerHostFragment. In the host Activity, put PagerHostFragment in place where ViewPager is required (either in XML, or by adding PagerHostFragment into FrameLayout). PagerHostFragment is a bit “dirty”, but this dirtiness is encapsulated and will not spread out.

      To summarize: there are cases where it is ok to have some “dirtiness points”, as long as this is a calculated trade-off and the dirtiness is encapsulated inside a single component.

      Reply
  6. Hello Alexey, and thanks for this great tutorial!

    Really. I am a begginner on Android and have been trying to understand the topic for a week now.
    Every other tutorials I’ve found so far were either to abstract, focusing only on high level explanation,
    or had terrific amount of hard-to-understand code examples.
    So cool I found your article, can’t thank you enough. It is so clear and intuitive as I suppose it should be.

    However, there are still some concepts I can’t catch on. Like for example:
    This is the chain of events happening after user taps a “Mark as read” Button (correct me if I’m wrong):

    1) onClick(View view) method of the mBtnMarkAsRead’s OnClickListener object is being called

    2) In it’s body mListener.onMarkAsReadClick() is being called

    3) In it’s body mSmsMessagesManager.markMessageAsRead(mSmsMessageId) is being called

    4) In it’s body the data is being updated (the sms value “read” is being changed to “true”)

    That’s it. It looks like this is the end.

    So my question is how th UI is updated after user clicks mBtnMarkAsRead ?
    I mean, it does not updates the appearence immediately after (like inside of the mBtnMarkAsRead’s onClick(View view) method).
    It seems the only place where this is happening is in the bindSmsMessage(SmsMessage smsMessage) method body. This method is called by the onSmsMessagesFetched(List smsMessages) method of the controller.
    And I can’t see where this method is being called in the chain of events after the mBtnMarkAsRead is being clicked which I described previously.
    In other words I don’t understand how the View is notified it has to change the appearence of the message representation after it is marked as read.

    Would ge great to hear your explanation. Again, thank you for this tutorial – it’s a grace.

    Reply
    • Hello Denis,
      Thanks for your feedback – I appreciate it very much.
      Indeed, the current implementation does not notify the view about changes. This is a bug. I already fixed it and pushed the fix into the repo.

      This bug was introduced when I refactored the implementation from Loaders to the current approach.
      One of the features of CursorLoader is that it automatically registers ContentObserver for the data it fetches, which allows for change notifications to be delivered without additional effort. When I ditched Loaders I forgot to implement this functionality myself.

      In order to keep the code simple, I did not implement a full blown ContentObserver scheme, but just added logic in SmsMessagesManager that re-fetches all the SMS messages and notifies listeners after the shown message is marked as read.

      This is yet another example of why unit-testing is an essential practice in software development. I did not unit test this code in order to keep the repo simple, but time after time lack of unit tests bites me in the a**.

      Thank you very much for catching this bug and taking time to report it.

      P.S. My name is Vasiliy )

      Reply
  7. Hello again Vasiliy,

    I’m trying to implement what I’ve learned from your tutorial in my own simplest MVC example.
    So far it is going well, however questions arrise from time to time. Like:

    1) In the MainActivity class in the replaceFragment(…) method you use view ID in the method
    ft.replace(R.id.frame_contents, …)

    Doesn’t it break the single responsibility principle since now activity becomes dependent on the UI component?
    I understand the neccecity of this: we have to tell fragment manager what view to populate with our new fragment.

    Wouldn’t something like mViewMVC.getRootView().getId() instead of R.id.frame_contents o the trick?
    I tried to do this replacement and launch the app: nothing seems to be broken so far.
    Are there any hidden pitfalls of this replacement?

    2) What about BackgroundThreadPoster and MainThreadPoster classes – why should they belong to the MvcTutorialApplication class rather than to MainActivity? What is the value of this?

    And one more about posters. I’m new to these concepts, could you please tell me: if my storage is going to be a web-server, and I’m going to use Retrofit, do I still need these? Since retrofit can on it’s own make sync and async operations without involving additional agents?

    3) It seems SmsMessagesManager is a concrete class, which extends BaseObservableManager so it could have functionality of registering and unregistering listeners (and get access to them).
    Am I right, that in the ideal spherical cow case it also should implement some sort of generic interface like this:

    public interface ISmsMessagesManager {

    fetchSmsMessageById(final log id);
    fetchAllSmsMessages();
    markMessageAsRead(final long id);
    notifySmsMessagesFetched(final List smsMessages);
    }

    So it’s implementations could be easily changed if our storage would change for example from internal storage to database or cloud-server?

    Again, thanks for your work, after careful reading through your code I consider it to be the cleanest code I’ve ever read so far.

    Reply
    • Hello Denis,
      These are very good questions.

      1) Yes, a reference to ID of the frame is indeed 1 “dirtiness point” as defined here. In IDoCare I mitigated the problem by abstracting all these dirty details into MainFrameHelper class, but if your solution works – it might be even better!

      2) Thread posters are my invention – these classes allow for easy and unit-testable multithreading. I need to find a time to wrap them into a library and present to the world. In general, multithreading is hard, and the associated bugs are the most difficult to find and fix. If your application doesn’t need special multithreading and you can offload it to the libraries (e.g. Retrofit) – that would be the best.

      3) Interfaces are powerful tools, but they should be used cautiously.
      If you already have multiple implementations, then sure – extract an interface for them. In this case, however, there is just one implementation, and this code is not very complicated. The value of an interface will be questionable, but each time a method will need to be added/removed you’ll have to make changes in 2 places.
      Therefore, in this case, I would say that interface is more of a burden. However, this is more of a taste issue than anything, so if you like having clear boundaries between classes – go on and extract interfaces for the managers.
      I already forsee your next question – why did I define interfaces for MVC views then?
      For this simple tutorial application it is also more of a burden, but I wanted to show the most general approach. In real applications, MVC views can be hundreds lines of code in length and have tens public methods (e.g. onClick()) – a clear interface allows for easy understanding of the contract, without a need to read the actual implementation.
      By the way, on one project I worked on we decided not to extract these interfaces and it also worked out very well, therefore this is also more of a taste thing.

      Thanks for the kind feedback – it really feels good to know that my ideas are of use to people πŸ™‚

      Reply
  8. Hello Vasiliy,
    Thanks for your answer.

    It seems for me now that we have at least two options:
    stick to interfaces right from the beginning or gradually extract them while a projects is growing. It is probably a matter of personal preferences.

    There’s one more thing I’m curious about considering your style of MVC pattern implementation.

    From what I understood decoupling of the MVCView from the Controller is immensely achieved by the fact that MVCView incapsulates UI logic and only provides pretty contract like onMarkThis() onCheckThat() etc.

    So keeping that in mind, let’s say we want to add a menu.

    1) One problem I see here is that to inflate menu from XML-resourse file we need a special kind of inflater – a MenuInflater. If we want our menu to be inflated in the MVCView, we should pass it the MenuInflater instance.
    I see two options:
    a) We may pass it through MVCView’s constructor in Controllers onCreate(…) method. This way if our Controller is a Fragment instance, we should first get the inflater from the wrapping activity.
    b) We may pass the inflater during the onCreateOptionsMenu(…). If so we should have an extra setter method in our MVCView since it will be already constructed by the time onCreateOptionsMenu(…) is called.

    In both cases we may than provide a getMenu() in the MVCView which should return the inflated menu,
    Not a big deal actually, and I think it can be mitigated by dependency injection.
    I just don’t understand what is so special about menus in Android that forces us to have an extra inflater.

    2) However even if we managed to inflate the menu in the MVCView, in my opinion we still loose the conceptual power of the MVC pattern here. Because there is no contract provided by the MVCView for the “menu case”. Instead we have onOptionsItemSelected(MenuItem item) method defined in the Controller itself.
    And now it is a duty of the Controller to decide what part of data should be accessible through interactions with the menu and what part – through interactions with other UI components. That is to say Controller now participates in making decisions on HOW to show the data, not only on WHAT data to show (let me borrow this description of UI and business logic from one of your comments).

    In your “Activities in Android are not UI Elements” article you did a great work describing how Activities in Android are inevitably bounded to busiess logic. Don’t you think that if we implement menus, Activities (and Fragments) also become coupled with UI logic in the same way?

    P.S. Thak you for allocating time to answer my questions here in your cozy blog πŸ™‚

    Reply
  9. Hi Vasily,

    I in my MVP implementation I got rid of fragments and I made ViewPager responsible for navigation between screens. I adjusted ViewPager’s
    adapter to work with MVC views. Then I realized that got rid of controllers of particular screens. And I ended up with one controller
    with instance of RootViewMvcImpl that returns rootView containing ViewPager. Here are my questions.

    Does lack of controllers for particular screens is a good solutions is it an anti-pattern?
    Is passing an instance of controller to particular screen through series of objects like RootViewMvcImpl, ViewPager adapter is a good solutions?

    Reply
    • Hey Damian,
      If you implemented ViewPager without Fragments, then you can have just one controller for all pages. However, if the pages contain lots of unrelated functionality, then your controller will grow in size and become a mess very quickly.
      In addition, don’t forget that FragmentStatePagerAdapter can be more memory efficient when it comes to ViewPager because it destroys the off-screen Fragments.
      So, I would say that if your ViewPager contains one type of functionality and there aren’t too many pages, then having one controller for all these pages is alright. However, if the pages represent different app’s functionality or there are just many of them, then you should consider the advantages of FragmentStatePagerAdapter.

      Reply
  10. Hi Vasily,

    Thanks for your great series of Post to help me understand what is MVC (or I’d prefer it is kind of MVP :))

    Well this probably is not a good question but it really confuses me a few time to make it straight, that is I see these 2 methods are looking similar to each other:

    1. onCreateView() –> mViewMVC.setListener(this);

    and

    2. onStart() –> mSmsMessagesManager.registerListener(this);

    I spent several minutes to make sure that the #1 is for handling the user event (e.g.: user clicks button)
    and
    the #2 is for handling the event message comes from XX_Manager (controller? model? Like you said no matter what it is, I understand it as the object work with data model) after data get returned/changed

    So I think it might be better to update the method names so user can distinguish them from each other easier, from the ViewInterface and BaseObservableManager, maybe:
    ViewInterface #setUserActionListener
    BaseObservableManager #registerControllerCallback

    I am not sure this will certainly be better but it makes them two not so look alike..

    Finally thanks again, I spend two days on your 4 articles and two projects, they are great!

    Reply
    • Hi Rain,
      Thanks for the feedback.
      I personally try to have the names of registration methods the same in all implementations of Observable, but it’s just a personal preference. If you think that your code will be more explicit if you change methods’ names – by all means do so.
      The only thing I’d like to note is that registerControllerCallback is not very good choice because the listeners aren’t necessarily controllers.
      In addition, this example is very old. Today I use very similar approach, but with different names and a bit different implementation. You might want to review the code of the tutorial application that I wrote for my Android Architecture course to see what I learned since I last updated this tutorial.
      And I probably need to update this tutorial as well…

      Reply
  11. Hi (again) Vasili,

    About the logic that the Controller does not contain. You gave an example that “no dependency on Android View class”. I checked out a Controller from the idocare app, the LoginChooserFragment. I can see that the latter imports the android.View class. Doesn’t this means that the Controller has a dependency on the Android’s View class?

    Thanks a lot

    Reply
    • Hey Themelis,
      IDoCare is not the “golden standard” of MVC. It was my first big Android project and I worked on it for more than three years (hopefully, I’ll get back to it on January). It’s also a sandbox where I test my ideas. For instance, it was IDoCare where I developed MVC as it looks today.
      That said, there is code in this project from more than three years ago. Some of that code was written long before I realized and formulated MVC rigorously, and some of that code was a deliberate trade-off on my part.
      So, keep all these disclaimers in mind when reviewing IDoCare’s code.
      Specifically, I reviewed this piece of code. There is a very hard dependency on View in this controller, and it implements quite big part of UI logic by itself. Today, I would call this code “dirty”.

      Reply
  12. Hi Vasiliy,

    First of all, thank you for this nice series.
    My question is about the Android Applications Architecture course –
    In part 1 of the series you said you prefer MVP over MVC for android. I do think it’s preferred and want to learn more about it.
    Will this course discuss only on MVC? what about MVP course do you have any? or this course can be suitable to me ?

    Reply
    • Hey Lior,
      You’re right, I said that in part 1. However, in part 2 I explained why this distinction is not that important and kind of arbitrary πŸ˜‰
      My Android Architecture course shows the most mature architectural pattern for Android development. I just recently learned that Netflix actually came up with quite a similar approach, which is a huge validation for the ideas I try to promote in the community.
      I call this pattern MVC, but you can call it MVP if you like this name more. It’s really not that important how you call it, as long as you understand the underlying theory and write clean code.
      If you’re professional Android developer with 6+ months of experience – the course is suitable for you. And there is 30-day money back guarantee in case it’ll not deliver on the promise.
      Hope this helps.

      Reply
  13. Hi,

    Right after i posted the comment saw your explanation πŸ™‚ thanks anyway for the immediate replay and i will check your course .

    Thanks again !

    Reply
  14. Hi
    Thanks for your good explanations. I was wondering if you can describe IDoCare app to show how Model notify View about changes and how Controller update Model and View briefly?

    Thanks πŸ™‚

    Reply
  15. Hi Vasiliy,
    Firstly, thank you for this series, I have learned a different approach in thinking of the Activity as the controller and not a view. And it makes a lot of sense. What I have seen elsewhere is that the Activity/Fragment is defined as the View with a separate Controller class that does not extend any Android class. I understand how I would unit test the controller in this scenario.
    I have checked out the example @ https://github.com/techyourchance/android_mvc_tutorial , But I don’t understand how I would unit test the business logic inside the Activity/Fragment controller. Would I still need to set up Espresso tests to test the business logic if I use the Activity/fragment as a controller?

    Reply
  16. Hmm, moderating? Good idea.

    Seems I need to change my previous post slightly. Perhaps the moderation could help. Or perhaps could make it irrelevant.

    It’s not the existence of the SetContentView that’s a problem, but the LoginActivity (& other top level activities in the example app) use R.layout references.

    My specific problem, which is not exactly down to what you’ve got here, is that I need to calculate sizes of a view to add to my base view, and if I do this in the constructor of the MVCView then the view hasn’t been fully inflated, since SetContentView does that, and hence my strategy fails.

    I s’pose I just need to refactor.

    Reply
    • Hello Mark,
      Sure, moderating. We live in a difficult and complex world πŸ™‚
      When you need to calculate the sizes of your views based on the post-inflation layout sizes, it’s real PITA. I recommend that you do anything withing your power to avoid that, but if you’re stuck and that’s the only path forward, look into global layout listeners.
      Vasiliy

      Reply
      • Thanks for that Vasiliy.

        Before I split the code in this style, I had global layout listener working quite happily. I think I’ve got some adjusting to do. I suspect lazy programming on my part is the problem.

        I *am* interested in how you see the listeners in this mode of working.
        It appeared from your sample app that the methods the listener interfaces expose are meant to be in the controller, but then I saw listeners within the views too.

        Is there a clear rule for which ones should be where?

        Reply
        • Hey Mark,
          MVC views can be nested within one another. You can see a more elaborate example in this tutorial app for my architecture course.
          BTW, if you want to use MVC in your projects, I honestly recommend that you take that course. It contains very detailed guidelines, more details and it’ll make your life so much easier. You can find the link on this blog.
          Cheers.

          Reply
  17. Hi Vasily,
    First and foremost, thank you for your great series of Posts FragmentLifecycle and MVC patterns.
    I’m joining and linking the tips presented in your posts:

    Let suppose we are using MVC over Fragments and we have to implement the save & restore flow :

    In the onSaveInstanceState(Bundle outState) part:
    After asking the view implementation for the current model. What should we save in the bundle?
    A: Only the necessary primitives.
    B: The whole model (Making it Parcelable).

    Or C: my approach is wrong or old. And your answer will be very educational for me.

    Thanks in advance.
    Francisco.

    Reply
    • Hey Francisco,
      If you have very little state, save primitives. Otherwise, use Parcelables or Serializable. I, personally, prefer Serializable.

      Reply

Leave a Comment

Subscribe for new posts