Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Shared Preferences in MVP without Dagger and not causing Presenter to be Context dependent?

I'm trying to implement MVP without Dagger (for learning purposes). But I got to the problem - I use Repository patter to get raw data either from cache (Shared Preferences) or network:

Shared Prefs|              |<->Repository<->Model<->Presenter<->View      Network| 

But to put my hands on Shared Preferences I have to put somewhere line like

presenter = new Presenter(getApplicationContext()); 

I use onRetainCustomNonConfigurationInstance/getLastCustomNonConfigurationInstance pair to keep Presenter "retained".

public class MyActivity extends AppCompatActivity implements MvpView {      @Override     protected void onCreate(Bundle savedInstanceState) {         //...         presenter = (MvpPresenter) getLastCustomNonConfigurationInstance();          if(null == presenter){             presenter = new Presenter(getApplicationContext());         }          presenter.attachView(this);     }      @Override     public Object onRetainCustomNonConfigurationInstance() {         return presenter;     }      //... } 

So how to use Shared Preferences in MVP without Dagger and not causing Presenter to be Context dependent?

like image 362
Marian Paździoch Avatar asked May 10 '16 11:05

Marian Paździoch


People also ask

What SharedPreferences method is used to get multiple preferences files identified by a name?

Get a handle to shared preferences You can create a new shared preference file or access an existing one by calling one of these methods: getSharedPreferences() — Use this if you need multiple shared preference files identified by name, which you specify with the first parameter.

What is mode private SharedPreferences?

MODE_PRIVATE means the file which created by your app for storing app preferences data that can be only accessible to your own app only. No other app would be able to access that file. Follow this answer to receive notifications.

What format is SharedPreferences?

Android Shared Preferences Overview Android stores Shared Preferences settings as XML file in shared_prefs folder under DATA/data/{application package} directory.


2 Answers

This is how I do it. I have a singleton "SharedPreferencesManager" class that will handle all the read write operations to shared prefs like below

public final class SharedPreferencesManager {     private  static final String MY_APP_PREFERENCES = "ca7eed88-2409-4de7-b529-52598af76734";     private static final String PREF_USER_LEARNED_DRAWER = "963dfbb5-5f25-4fa9-9a9e-6766bfebfda8";     ... // other shared preference keys      private SharedPreferences sharedPrefs;     private static SharedPreferencesManager instance;      private SharedPreferencesManager(Context context){         //using application context just to make sure we don't leak any activities         sharedPrefs = context.getApplicationContext().getSharedPreferences(MY_APP_PREFERENCES, Context.MODE_PRIVATE);     }      public static synchronized SharedPreferencesManager getInstance(Context context){         if(instance == null)             instance = new SharedPreferencesManager(context);          return instance;     }      public boolean isNavigationDrawerLearned(){         return sharedPrefs.getBoolean(PREF_USER_LEARNED_DRAWER, false);     }      public void setNavigationDrawerLearned(boolean value){         SharedPreferences.Editor editor = sharedPrefs.edit();         editor.putBoolean(PREF_USER_LEARNED_DRAWER, value);         editor.apply();     }      ... // other shared preference accessors } 

Then whenever access to shared preference is needed I pass the SharedPreferencesManager object in the relevant Presenter's constructor. For example :

if(null == presenter){     presenter = new Presenter(SharedPreferencesManager.getInstance(getApplicationContext())); } 

Hope this helps!

like image 45
Much Overflow Avatar answered Sep 22 '22 11:09

Much Overflow


Your Presenter should not be Context dependent in the first place. If your presenter needs SharedPreferences you should pass them in the constructor.
If your presenter needs a Repository, again, put that in the constructor. I highly suggest watching Google clean code talks since they do a really good job explaining why you should use a proper API.

This is proper dependency management, which will help you write clean, maintainable, and testable code. And whether you use dagger, some other DI tool, or supply the objects yourself is irrelevant.

public class MyActivity extends AppCompatActivity implements MvpView {      @Override     protected void onCreate(Bundle savedInstanceState) {         SharedPreferences preferences = // get your preferences         ApiClient apiClient = // get your network handling object         Repository repository = new Repository(apiClient, preferences);         presenter = new Presenter(repository);     } } 

This object creation can be simplified by using a factory pattern, or some DI framework like dagger, but as you can see above neither Repository nor your presenter depends on a Context. If you want to supply your actual SharedPreferences only their creation of them will depend on the context.

Your repository depends on some API client and SharedPreferences, your presenter depends on the Repository. Both classes can easily be tested by just supplying mocked objects to them.

Without any static code. Without any side effects.

like image 107
David Medenjak Avatar answered Sep 22 '22 11:09

David Medenjak