Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android MVP: safe use Context in Presenter

In my app I work with ContentProvider and use LoaderManager.LoaderCallbacks<Cursor>.

Fragment (View)

public class ArticleCatalogFragment extends BaseFragment
        implements ArticleCatalogPresenter.View,
        LoaderManager.LoaderCallbacks<Cursor> {

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return onCreateArticleCatalogLoader(args);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {        
         data.registerContentObserver(new LoaderContentObserver(new Handler(), loader));
         updateUI(data);        
    }   

    private Loader onCreateArticleCatalogLoader(Bundle args) {
            int categoryId = args.getInt(CATEGORY_ID);
            Loader loader = new ArticleCatalogLoader(this.getActivity(), categoryId);            
            return loader;
    }

}

From point of view MVP I need:

Presenter

public class ArticleCatalogPresenter extends BasePresenter
        implements LoaderManager.LoaderCallbacks<Cursor> {

    View view;

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        return onCreateArticleCatalogLoader(args);
    }

    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {        
         data.registerContentObserver(new LoaderContentObserver(new Handler(), loader));
         view.updateUI(data);        
    }               

    private Loader onCreateArticleCatalogLoader(Bundle args) {    
            int categoryId = args.getInt(CATEGORY_ID);
            Loader loader = new ArticleCatalogLoader(context, categoryId); // need Context
            return loader;
    }


    interface View {
        updateUI(Cursor data)
    }

}

So, I need a context in Presenter.

There are some nuances:

  1. Presenter know about the Context - it is bad, Presenter should not know about the Android.

  2. Having a Context in Presenter can lead to memory leak.

I am now worried about how to avoid problems such as memory leaks, and how best pass Context in Presenter, use Application Context or Activity/Fragment?

like image 301
Alexandr Avatar asked Aug 11 '15 20:08

Alexandr


People also ask

Should we provide a context in presenter model?

I would strongly suggest that the presenter should have no concept of the Android Context (or any other Android classes). By completely separating your Presenter code from the Android system code you are able to test it on the JVM without the complication of mocking system components.

How does MVP work in Android?

What is MVP? The MVP pattern allows separating the presentation layer from the logic so that everything about how the UI works is agnostic from how we represent it on screen. Ideally, the MVP pattern would achieve that the same logic might have completely different and interchangeable views.

What is MVP in Android App?

MVP (Model — View — Presenter) comes into the picture as an alternative to the traditional MVC (Model — View — Controller) architecture pattern. Using MVC as the software architecture, developers end up with the following difficulties: Most of the core business logic resides in Controller.

What is a presenter in Android?

A Presenter is used to generate View s and bind Objects to them on demand. It is closely related to the concept of an RecyclerView. Adapter , but is not position-based. The leanback framework implements the adapter concept using ObjectAdapter which refers to a Presenter (or PresenterSelector ) instance.


1 Answers

Adding context to Presenter is not good since, the presenter is responsible for business logic. To deal with context, you need to have the Fragment/Activities make use of Callbacks with the help of interfaces which will state what actions need to be perform by the activity/fragment when dealing with views. Fragment / Activities are responsible to provide Context.

Example:

interface BaseContract {
        interface BaseView {
            //Methods for View
            void onDoSomething();
        }

        interface BasePresenter {
            void doSomething();

        }
    }

    class BaseMainPresenter implements BaseContract.BasePresenter {
        BaseContract.BaseView view;

        BaseMainPresenter(BaseContract.BaseView view) {
            this.view = view;
        }

        @Override
        public void doSomething() {
            if (view != null)
                view.onDoSomething();
        }
    }

    class DemoClass implements BaseContract.BaseView {

        //Create object of Presenter 

        /****
         * Example :
         * BaseMainPresenter baseMainPresenter = new BaseMainPresenter(this);
         */
        @Override
        public void onDoSomething() {
            //Deal with Context here.
        }
    }
like image 148
Archis Thakkar Avatar answered Sep 21 '22 08:09

Archis Thakkar