Accessing Sharedpreferences Through Static Methods

Accessing SharedPreferences through static methods

That's because in this case, act is an object that you just create. You have to let Android do that for you; getSharedPreferences() is a method of Context, (Activity, Service and other classes extends from Context). So, you have to make your choice:

  • If the method is inside an activity or other kind of context:

    getApplicationContext().getSharedPreferences("foo", 0);
  • If the method is outside an activity or other kind of context:

    // you have to pass the context to it. In your case:
    // this is inside a public class
    public static SharedPreferences getSharedPreferences (Context ctxt) {
    return ctxt.getSharedPreferences("FILE", 0);
    }

    // and, this is in your activity
    YourClass.this.getSharedPreferences(YourClass.this.getApplicationContext());

Static SharedPreferences

You could save and load from Application-wide shared preferences instead of prefs private to the Activity:

private static boolean load(String tag) {
SharedPreferences sharedPreferences = Context.getApplicationContext().getSharedPreferences("namespace", Context.MODE_PRIVATE);
return sharedPreferences.getBoolean(tag, false);
}

If you do this, make sure you are also storing the preferences in the same way (by using Context.getApplicationContext().getSharedPreferences)

When to use static variable and sharedpreference in android

You can use static when there is not huge amount of data in the application.
sharedpreference can be used if the data is more also and can be stored and retrieved as and when it is required.

Is it safe to keep a static reference to a SharedPreferences and its Editor?

To answer the question authoritatively, it is safe to store the SharedPreferences instance as a static reference. According to the javadocs it is a singleton, so its source from getSharedPreferences is already a static reference.

It is not safe to store the SharedPreferences.Editor because it is possible two threads may be manipulating the same editor object at the same time. Granted, the damage this would cause is relatively minor if you happen to have already been doing it. Instead, get an instance of an editor in each editing method.

I highly recommend using a static reference to your Application object instead of passing in Context objects for every get. All instances of your Application class are singletons per process anyways, and passing around Context objects is usually bad practice because it tends to lead to memory leaks via reference holding, and is unnecessarily verbose.

Finally, to answer the unasked question if you should lazily-load or greedily-initialize the reference to your static SharedPreferences, you should lazily load in a static getter method. It may work to greedily-initialize a reference with final static SharedPreferences sReference = YourApplication.getInstance().getSharedPreferences() depending on the chain of class imports, but it would be too easy for the class loader to initialize the reference before the Application has already called onCreate (where you would initialize the YourApplication reference), causing a null-pointer exception. In summary:

class YourApplication {
private static YourApplication sInstance;

public void onCreate() {
super.onCreate();
sInstance = this;
}
public static YourApplication get() {
return sInstance;
}
}

class YourPreferencesClass {
private static YourPreferencesClass sInstance;
private final SharedPreferences mPrefs;

public static YourPreferencesClass get() {
if (sInstance == null)
sInstance = new YourPreferencesClass();
return sInstance;
}

private final YourPreferencesClass() {
mPrefs = YourApplication.get().getSharedPreferences("Prefs", 0);
}

public void setValue(int value) {
mPrefs.edit().putInt("value", value).apply();
}

public int getValue() {
return mPrefs.getInt("value", 0);
}
}

You will then use your statically available preferences class as such:

YourPreferencesClass.get().setValue(1);

A final word about the thread-safety and memory observability. Some astute observers may notice that YourPreferencesClass.get() isn't synchronized, and hence dangerous because two threads may initialize two different objects. However, you can safely avoid synchronization. As I mentioned earlier, getSharedPreferences already returns a single static reference, so even in the extremely rare case of sInstance being set twice, the same underlying reference to SharedPreferences is used. Regarding the static instance of YourApplication.sInstance, it is also safe without synchronization or the volatile keyword. There are no user threads in your application running before YourApplication.onCreate, and therefore the happens-before relationship defined for newly created threads ensures that the static reference will be visible to all future threads that may access said reference.

How to reference getSharedPreferences from a static context that is not an Activity

to use the sharedPreferences you need to have the activity, so there's a lot of options here:

  • if you're using fragments then you need activity to get applicationContext,
    you can get an activity by calling requireActivity() on your fragment object.

  • then get a SharedPreferences reference to your data through this line of code.

Context context = requireActivity().getApplicationContext();
SharedPreferences sharedPref = context.getSharedPreferences(
"mySharedPrefData", Context.MODE_PRIVATE);
  • then you can send this sharedPref reference through the adapter constructor when you initialize it.
    so your adapter constructor code should look like this :
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewholder> {
SharedPreferences myShared ;
public MyAdapter (SharedPreferences shared){
myShared = shared ;
}
}

which from now on you can use the myShared variable to access your shared preferences inside your adapter.

N.B : if you're not using fragments and initializing your adapter inside your main activity directly, then you can skip the requireActivity part and your shared preferences code will look like this instead

Context context = getApplicationContext();
SharedPreferences sharedPref = context.getSharedPreferences(
"mySharedPrefData", Context.MODE_PRIVATE);

Update

  • since there's some confusion let me clarify that you should use the getApplicationContext() call inside your activity, assuming you initialize your adapter in onCreate method inside activity, then your MainActivity code might look like this :
public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
...
Context context = getApplicationContext();
SharedPreferences sharedPref = context.getSharedPreferences(
"mySharedPrefData", Context.MODE_PRIVATE);
MyAdapter myAdapter = new myAdapter(sharedPref);
...
}
}

N.B : three dots (...) means that I don't care about your code written here.

Update

  • if you don't have the permission to edit the adapter constructor parameters then what about making a setter to it.

MyAdapter.java

    public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyViewholder> {
SharedPreferences myShared ;
public MyAdapter (SomeOtherParameter){...}
public void setMyShared(SharedPreferences shared){
myShared = shared ;
}
}
  • then after initializing your adapter, you set the shared Preferences to it

MainActivity.java

public class MainActivity extends AppCompatActivity {


@Override
protected void onCreate(Bundle savedInstanceState) {
...
Context context = getApplicationContext();
SharedPreferences sharedPref = context.getSharedPreferences(
"mySharedPrefData", Context.MODE_PRIVATE);
MyAdapter myAdapter = new myAdapter(SomeOtherParameter);
myAdapter.setMyShared(sharedPref);
...
}
}

N.B : if you used the code above then don't use the myShared object in any case in the adapter constructor to avoid NullPointerException

Why Static Shared Preferences are not saved?

Try this:

SharedPreferences.Editor editor = getSharedPrefferences().edit();
editor.putBoolean("DBSyncNeeded", value);
editor.commit();

You have to remember to update the changes made to the SharedPreferences, so SharedPreferences actually save it.

Inserted into your code:

public static void setSyncDBIsNeeded(boolean value) {
Log.d("PREFCON","Setted DBSyncNeeded : "+value);
SharedPreferences.Editor editor = getSharedPrefferences().edit();
editor.putBoolean("DBSyncNeeded", value);
boolean completed = editor.commit();
Log.e("PREFCON", "Updating SharedPreferences was " + completed + "!";
}

By adding a boolean value to be set to editor.commit you can easily know if it was a success or not. According to the documentation the commit() method returns a boolean value based on if it completed or not. True means the editing was successfull, while false means something went wrong.

SharedPreferences - Static string in Static Class?

This code is okay if you are calling from inside an activity because the this keyword refers to your current activity instance.

String sName = SharedPrefs.getserverName(this);

Make sure that you have a reference to the context object inside your static Connection class. Let's say your context object is referenced by the context variable, do this:

String sName = SharedPrefs.getserverName(context);


Related Topics



Leave a reply



Submit