简体   繁体   中英

Android - MVP using Activity/Context

I've been dabbling with MVP for android and have read from different sites about not passing an activity as argument into the presenter as it's anti-pattern but i have come across a problem where i need to use a third party method that requires the activity/context.

I've thought of using Dependency Injection, doing another abstraction or just pass it only to the method that requires it, rather than the constructor but i'm confused with what's better.

An example in Kotlin (Presenter)

fun Food(*should activity be passed here?*) { 
var bar = Foo(activity).build

Stand(bar, callback{})
}

Would be great if someone can enlighten me on this.

I don't think any obvious reason why you should avoid passing Activity Context to Presenter. I heard that you should make presenter independent of any Android packages because you can reuse them for Desktop/TV or other platforms, but I don't think this will work.

If you need activity in your presenter you have several ways to do it (my DI cases will use Dagger2 library but you can take a look at another ones):

  • Just pass activity in setter/constructor, to make it safer use WeakReference. This is how we do it in our project.

    public class BasePresenter implements IPresenter {

     protected VIEW view; private WeakReference<FragmentActivity> activityWeakReference = new WeakReference<>(null); @Override public void onStart(FragmentActivity activity) { activityWeakReference = new WeakReference<>(activity); } @Override public void onStop() { activityWeakReference.clear(); } @Override public void onViewCreated(Bundle savedInstanceState) { } public Optional<FragmentActivity> getActivity() { return Optional.ofNullable(activityWeakReference.get()); } public void getActivity(Action1<FragmentActivity> action) { getActivity().ifPresent(action::call); } @Override public void setView(VIEW view) { this.view = view; } @Override public boolean onBackPressed() { return false; } @Override public void navigationButtonClick() { getActivity(Activity::finish); } @Override public boolean onCustomActivityResult(int requestCode, int resultCode, Intent data) { return false; }} 
    • You can provide your context to dagger modules like this .

    • You can use Dagger Android Injector. Personally I'm not a big fan of it but this should work. Read this article .

Do not forget to null your activity when presenter not needed anymore, because they are huge in memory so it will cause leaks.

If you want to work in a "clean way" you should always push the frameworks (android, third party libraries, data sources...) to the outer layer of your architecture (as far as possible from your business logic).

In your case I would create a "wrapper class" for the 3rd party library and the context and I would inject the interface of this class as a constructor parameter of your presenter. In this way your presenter is clean and is not affected if you have to change the 3rd party library.

Here you can read more about clean architecture:

https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html

https://github.com/android10/Android-CleanArchitecture

https://android.jlelse.eu/a-complete-idiots-guide-to-clean-architecture-2422f428946f

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM