I have a PrefUtils class like this:
public class PrefUtils {
public PrefUtils() {
}
private static SharedPreferences getSharedPreferences(Context context) {
return context.getSharedPreferences("APP_PREF", Context.MODE_PRIVATE);
}
public static void storeAccessToken(Context context, String access_token) {
SharedPreferences.Editor editor = getSharedPreferences(context).edit();
editor.putString("Access_Token", access_token);
editor.commit();
}
public static String getAccessToken(Context context) {
return getSharedPreferences(context).getString("Access_Token", null);
}
}
In my MainActivity I have a static method and I should use a static Context for it :
public class MainActivity extends AppCompatActivity {
private static Context mcontex;
// Is It right To Add Context To static Variable???
#SuppressLint("CheckResult")
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
my_method();
}
public static void my_method(){
String access_token =PrefUtils.getAccessToken(mcontex);
// more code ...
}
}
Is it right to add Context to a static variable?
Android Studio says: "Do not place Android Context class in static field".
Does this cause an error like memory leak? And if answer is Yes, what is the right way?
Pass the Context as a parameter to the method rather than keeping the context in a static variable.
public static void myMethod(#NonNull Context context){
String access_token =PrefUtils.getAccessToken(context);
// more code ...
}
The downside of having a static context variable is that there is no guarantee that the non-static onCreate() will have been called before some static initialization code tries to fetch your static Context object. That means your calling code will need to be ready to deal with null values.
Related
I am an android beginner and tried almost every method to use Shared Preferences but when I try to get value in nonactivity class method doesn't work ONLY IF APP REMOVED FROM RECENT APPS.
My Scenario is like:
Class LocationRequestHelper.java
import android.content.Context;
import android.preference.PreferenceManager;
public class LocationRequestHelper {
...
...
public static String getUserId() {
return MainActivity.preferences.getString("userId","");
}
public static void setUserId(String userId) {
MainActivity.preferences.edit().putString("userId", userId ).commit();
}
}
MainActivity
public class MainActivity extends FragmentActivity implements
SharedPreferences.OnSharedPreferenceChangeListener {
public static SharedPreferences preferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
preferences = PreferenceManager.getDefaultSharedPreferences(this);
LocationRequestHelper.setUserId("1");
....
....
Utils
public class Utils {
public static void getLocationUpdates(final Context context, final Intent intent, String broadcastevent){
LocationResult result = LocationResult.extractResult(intent);
if (result != null) {
List<Location> locations = result.getLocations();
Location firstLocation = locations.get(0);
accuracy = firstLocation.getAccuracy();
LocationData data = new LocationData();
// MY FUNCTION DOESN'T WORK HERE
data.setUsrid(LocationRequestHelper.getUserId());
updateServer(data);
}
}
getLocationUpdates is called from BroadcastReceiver
Now problems appears after I try to get userID using
LocationRequestHelper.getUserId();
EDITED : Added Broadcast code
LocationUpdatesBroadcastReceiver
public class LocationUpdatesBroadcastReceiver extends BroadcastReceiver {
private static final String TAG = "LUBroadcastReceiver";
public static final String ACTION_PROCESS_UPDATES ="PROCESS_UPDATES";
#Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
final String action = intent.getAction();
if (ACTION_PROCESS_UPDATES.equals(action)) {
Utils.getLocationUpdates(context,intent,"PROCESS_UPDATES");
}
}
}
}
NOTE:: THIS WORKS FINE IF APP IS IN BACKGROUND. BUT CRASHES AFTER I KILL FROM RECENT APPS.
Please tell me how I can send saved user id in my api call?
sorry for caps but this is main problem :P
The reason the app is crashing is that when it is killed any static variables become null. However you are still trying to access the SharedPreferences from the broadcast receiver and as such are getting a NPE.
The first thing you can do is update your LocationRequestHelper class to accept a context in the method rather than using the static SharedPreferences:
public class LocationRequestHelper {
//...
public static String getUserId(Context context) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
return prefs.getString("userId","");
}
public static void setUserId(Context context, String userId) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
prefs.edit().putString("userId", userId ).commit();
}
}
Then update you MainActivity to get rid of the SharedPrefs business and change the call to:
LocationRequestHelper.setUserId(this, "1");
And the Utils class to:
data.setUsrid(context, LocationRequestHelper.getUserId());
To get context, I use:
Context context = InstrumentationRegistry.getInstrumentation().getContext();
But I didn't found any method like getApplicationContext();
Any leads would be appreciated
Try this way:
Your_Activity.this
Or you can create a public static method to get the Context:
public class App extends Application {
private static Application sApplication;
public static Application getApplication() {
return sApplication;
}
public static Context getContext() {
return getApplication().getApplicationContext();
}
#Override
public void onCreate() {
super.onCreate();
sApplication = this;
}
}
Or get it through a View, using Your_View.getContext()
Hope this help
I am trying to create a global variable where it can be accessed from any any where including Activity, Fragment and other custom classes.
public class Global extends Application {
private static Global sInstance;
private String mSharedInfoFileName; //can be any custom object
public static Global getInstance() { return sInstance; }
#Override
public void onCreate() {
super.onCreate();
sInstance = this;
initialize();
}
private void initialize() { mSharedInfoFileName = "globalInfo"; }
public String getFileName() { return mSharedInfoFileName; }
private Global() { }
}
and try to use it like this
public class MyFragment extends android.support.v4.app.Fragment {
String s = Global.getInstance().getFileName();
}
even after declaring it in class scope still gave same error
private static Global mGlobal = Global.getInstance();
which give me Attempt to invoice... .Global.getFileName()' on a null object reference. What am I missing?
Thank you
Change this method to static :
public static String getFileName() {
return mSharedInfoFileName;
}
and call it like below:
Global.getFileName();
The mSharedInfoFileName variable has to be static too :
private static String mSharedInfoFileName;
I know I can use getApplicationContext() to get Context from sub class of ListActivity.
but PublicPar is common class, how can I get Context from this class.
public class SMSMain extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
Context my=getApplicationContext();
}
}
public class PublicPar {
public static void SetNotification(){
}
}
If you have a common (helper-type) class like your PublicPar class, the best you can do is to pass context as a parameter to each method:
public static void SetNotification(Context context) {
}
Remember to not set this context to any PublicPar class variable to avoid leaking it.
Try this. It should work:
public class SMSMain extends ListActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
// Context my=getApplicationContext();
new PublicPar().SetNotification(SMSMain.this)
}
}
public class PublicPar {
public static void SetNotification(final Context context ){
// You can proceed with using the context here.
}
}
If you don't want to pass the Context around as part of constructor argument, you can expose a static method in the application.
public class MyApplication extends Application {
private static MyApplication myinstance;
public MyApplication() {
myinstance = this;
}
public static Context getAppContext() {
myinstance.getApplicationContext();
}
}
How to pass application context from Singleton class to SharedPreferences? I have a fragment and a GridView inside its onActivityCreated(Bundle savedInstanceState) method , on item-click, I am getting NullPointerException in logcat:
03-30 05:12:54.784: E/AndroidRuntime(1950): FATAL EXCEPTION: main
03-30 05:12:54.784: E/AndroidRuntime(1950): java.lang.NullPointerException
03-30 05:12:54.784: E/AndroidRuntime(1950): at android.preference.PreferenceManager.getDefaultSharedPreferencesName(PreferenceManager.java:374)
03-30 05:12:54.784: E/AndroidRuntime(1950): at android.preference.PreferenceManager.getDefaultSharedPreferences(PreferenceManager.java:369)
03-30 05:12:54.784: E/AndroidRuntime(1950): at com.example.duaapp.utility.SharedPreferencesSupplication.save(SharedPreferencesSupplication.java:35)
Singleton Class
public class SingletonClass {
public static Context applicationContext;
public static int fontSizeMin = 17;
public static int fontSizeMax = 35;
public static final String keySelVerseFromList = "keySelVerseFromList";
public static final String keyFavVerses = "keyFavVerses";
public static final String keyListOfVerses = "keyListOfVerses";
public static final String keyIsFavSelected = "keyIsFavSelected";
}
SharedPreferences
public class SharedPreferencesSupplication {
public void save(String valueKey, String value) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SingletonClass.applicationContext);
SharedPreferences.Editor edit = prefs.edit();
edit.putString(valueKey, value);
edit.commit();
}
public void save(String valueKey, int value) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SingletonClass.applicationContext);
SharedPreferences.Editor edit = prefs.edit();
edit.putInt(valueKey, value);
edit.commit();
}
public void save(String valueKey, boolean value) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SingletonClass.applicationContext);
SharedPreferences.Editor edit = prefs.edit();
edit.putBoolean(valueKey, value);
edit.commit();
}
public void save(String valueKey, long value) {
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(SingletonClass.applicationContext);
SharedPreferences.Editor edit = prefs.edit();
edit.putLong(valueKey, value);
edit.commit();
}
}
On gridview_item_Click, whenever new SharedPreferencesSupplication().save(SingletonClass.keyIsFavSelected, false); is called, the app crashes and nullpointer exception is raised in logcat. Where am I going wrong?
Never use static references to Context in Android, this will cause you an important memory leak since Context has references to all the application resources.
Most of the Android UI classes have a dynamic reference to the context, in fragments you can do getActivity(), in views getContext() consider using those instead of context singletons
More information about this here
While Guillermo Merino concern is valid, an application Context used in a singleton class should not be automatically considered a memory leak.
Calling context.getApplicationContext() will, regardless of where or how it is accessed, always return the same instance from within your process. It will be "alive" for at least as long as the singleton will, therefore holding a reference to it should do no harm.
That said, it might not be enough to perform certain operations, as Dave Smith describes in his blog post.
Since OP is trying to access default SharedPreferences, this could be achieved using just application Context, e.g.:
// Custom Application class.
public class MyApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
SingletonClass.INSTANCE.init(getApplicationContext());
}
}
// Singleton.
public enum SingletonClass {
INSTANCE;
private Context applicationContext;
public static int fontSizeMin = 17;
public static int fontSizeMax = 35;
public static final String keySelVerseFromList = "keySelVerseFromList";
public static final String keyFavVerses = "keyFavVerses";
public static final String keyListOfVerses = "keyListOfVerses";
public static final String keyIsFavSelected = "keyIsFavSelected";
// Make sure you only call this once - from MyApplication.
public void init(final Context context) {
applicationContext = context.getApplicationContext();
}
public Context getApplicationContext() {
if (null == applicationContext) {
throw new IllegalStateException("have you called init(context)?");
}
return applicationContext;
}
}
I don't believe this would cause any memory leaks, but if I'm mistaken, please do correct me.