Custom Class extends Application for Singleton Purposes - android

I tried to create custom class to fetch some values from SharedPreferences.
My aim is to reach to that values from any class.
I am getting null Pointer exception on
SharedPreferences prefs = getApplicationContext().getSharedPreferences("UserFile", MODE_PRIVATE);
My code is as below;
public class UserInfo extends Application {
private String token;
private String SAVED_USERNAME;
public UserInfo() {
SharedPreferences prefs = getApplicationContext().getSharedPreferences("UserFile", MODE_PRIVATE);
token = prefs.getString("Token", null);
}
public String getToken() {
return token;
}
}
What might be the wrong?

Usually Android components are initialized during their lifecycle. In this particular case you can't access application Context and SharedPreferences because they're not initialized yet.
Second problem might be (thanks to my crystall ball) that you did not added your Application to AndroidManifest
So, your first thought might be to move initialization code from constructor to onCreate. This would solve this particular problem.
However, it's a bad practice to do what you're doing. Because there can be only 1 Application component per application. This will limit you to 1 such singleton per app. Consider using Application to provide application Context as singleton and create another singleton for providing UserInfo.
No examples, please exercise yourself.

Just have this method in a util class. No need to extend application.
public static String getToken(Context context) {
return PreferenceManager.getDefaultSharedPreferences(context).getString("Token", null);
}

There is a rule in android - don't use constructor of app component: Activity/Fragment/Application/Service... there is onCreate() method, because in your constructor context will be null. So move your code to onCreate(). Also you need set your UserInfo as application in Manifest.

You don't create constructor of Application class instead, use the code in onCreate():
#Override
public void onCreate() {
super.onCreate();
SharedPreferences prefs = getApplicationContext().getSharedPreferences("UserFile", MODE_PRIVATE);
token = prefs.getString("Token", null);
}
and use it from any activity:
UserInfo userInfo = (UserInfo)getApplication();
String token = userInfo.getToken();

public class MyApp extends Application {
private static MyApp _instance;
#Override
public void onCreate() {
super.onCreate();
_instance = this;
}
public static MyApp getInstance(){
return _instance;
}
public String getToken() {
return getSharedPreferences("UserFile", MODE_PRIVATE).getString("Token", null);
}
}
In your manifest:
<application
android:name="your.package.MyApp"
>
If you whant use :
String token = MyApp.getInstance().getToken();

Make sure you have registered this class in your AndroidManifest.XML file.
<application android:name=".UserInfo"
...
/>
Note: Your way for accessing shared preferences does not seem good. I rather myself declare a class named PreferencesHelper and put all preferences stuff there.
public class PreferencesHelper{
private SharedPreferences mPrefs;
public PreferencesHelper(Context context){
this.mPrefs = context.getSharedPreferences("name", Context.MODE_PRIVATE);
}
public getToken() {
return mPrefs.getString("Token", null);
}
public String setToken(String token) {
mPrefs.edit().putString("Token", token).apply();
}
}

Related

Updating an object stored in one Activity from another activity

I am creating an object called "AppEngine" inside my first activity. This AppEngine object stores and arrayList of Events, and begins with 2 events inside it.
From the first Activity I click a button which takes me to a second Activity in which I add an event object to the arrayList by using.
appEngine.getList.add(new Event)
When inside Activity 2, If I am to call appEngine.getList.size() the size is correctly returned as 3 and I can see the extra event.
When I switch back to Activity 2, I am calling appEngine.getList.size()however it only returns 2, and the extra event is not in there. How can i get the appEngine object to update?
save your array list in shared preference like this create a AppPreference Class:-
public class AppPreference {
private static SharedPreferences mPrefs;
private static SharedPreferences.Editor mPrefsEditor;
public static Set<AppEngine> getList(Context ctx) {
mPrefs = PreferenceManager.getDefaultSharedPreferences(ctx);
return mPrefs.getStringSet("AppEngineList", null);
}
public static void setList(Context ctx, ArrayList<AppEngine> value) {
mPrefs = PreferenceManager.getDefaultSharedPreferences(ctx);
mPrefsEditor = mPrefs.edit();
Set<String> set = new HashSet<>();
set.addAll(value);
mPrefsEditor.putStringSet("AppEngineList", set);
mPrefsEditor.commit();
}
}
set your value from first activity like this:-
setList(YourActivity.class, list);
and get your list from anywhere in you app:-
ArrayLis<AppEngine> list = AppPreference.getList(yourActivity.class);
If you only want the appEnginge object to persist during a single app session and not persist trough a complete app close/restart, then you should use a handler class.
EngineHandler.java:
public static class engineHandler {
public static appEnginge _appEngine;
}
and then just call
engineHandler._appEngine = _myAppengine;
engineHandler._appEngine.getList().add(new Event);
from your activity(s). The engineHandler will be accessible from any activity in your application.
You can use Singleton design Pattern.
You create one object from AppEnginRepository with eventList field and in your app you just get it and each time you want, you change it.
public class AppEnginRepository {
private List<Event> eventList;
private static final AppEnginRepository ourInstance = new AppEnginRepository();
public static AppEnginRepository getInstance() {
return ourInstance;
}
private AppEnginRepository() {
eventList = new ArrayList<>();
}
public List<Event> getEventList() {
return eventList;
}
public void setEventList(List<Event> eventList) {
this.eventList = eventList;
}
}
In your Activities
AppEnginRepository enginRepository=AppEnginRepository.getInstance();
List<Event> eventList=enginRepository.getEventList();
eventList.add(new Event());
int eventListSize=eventList.size();
It would be good to think each Activity is totally separated execution. Technically it's arguable, but it is good assumption to design cleaner and safer software.
Given assumption, there are several approaches to maintain data across Activities in an app.
As #Sandeep Malik's answer, use SharedPreference OS-given storage.
Similar to #Joachim Haglund's answer, use Singleton pattern to maintain an object in app.
Or, use small database like Realm.
Every approach has similar fashion; there should be an isolated and independent storage which is not belonged to one of Activity but belonged to ApplicationContext or underlying framework.

How to access sharedpreference value in non-Activity Java class?

I want to get Shared preference values in non-Activity Url Constants class where I need to check url which will come from a previous Activity. I am using common Shared Preference Utility class where I am using Shared Preference Manager to put and get values through shared preferences; however whenever I try to access shared preference value in Url constants class, I cannot access the common shared preference utility class. How can I get the value ? Please help.
My Shared Preference class is:
public class Preference {
private static final String PREFIX = "json";
public static void setString(String key, String value, Context context) {
SharedPreferences prefs =
PreferenceManager.getDefaultSharedPreferences(context);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(key, value);
editor.apply();
}
public static String getString(String key, Context context) {
SharedPreferences preferences =
PreferenceManager.getDefaultSharedPreferences(context);
return preferences.getString(key, null);
}
You should pass context, instead doing any hacks with context
Ideally, we should get this done once and access it anywhere. What I mean is we can create a single instance of Sharedpreference when starting Application class and make any calls on this object.
public class AppController extends Application {
static AppController appController;
public static AppController getInstance(){
return appController;
}
#Override
public void onCreate() {
super.onCreate();
Fabric.with(this, new Crashlytics());
appController = this;
}
}
get it named in manifest first before use in application tag with name attribute.
<application
android:name=".AppController"
......
......
</application>
So we can initialize here our SharedPreference or get application instance like this. We can also use Dagger for this and do much more.
AppController.getInstance().getApplicationContext().getSharedPreferences("userdetails", MODE_PRIVATE);
OR
we can just pass context to some constructor of a non-actvitiy/fragment class.
AS show your code you pass context that's not problem but the problem with your class name Preference it should be similar to java inbuilt class like java.android.preference and java.util.pref so make sure you are pointing your project class not android java default calss. or you may try to change your util class with other

How do I access Android SharedPreferences from a static method in a class without passing in a context reference?

I have just one class where I need to access SharedPreferences:
public class MyUtils {
public static String packageMe(Object input){
// do stuff here
// need SharedPreferences here
}
public static Object unpackageMe(String input){
// do stuff here
// need SharedPreferences here
}
}
I tried this:
public class MyUtils extends Activity
But, as you know, I cannot access SharedPreferences from a static method.
I thought about passing in the context to the static methods, but that extends the number of classes out to four that I will need to modify, and the classes are already extending AsyncTask:
public class SomeClass01 extends AsyncTask {
#Override
protected Object doInBackground(Object[] params){
MyUtils.packageMe(abc_123_object);
// do stuff here
}
}
So, I thought that maybe I could pass the context into those four classes. However, there are a couple dozen classes that I would need to modify that use those four classes, that in turn use that single class.
public class SomeTopClass extends FragmentActivity implements x, y, z {
new SomeClass01.execute(abc_123_object);
// do stuff here
}
I don't know if I want to be passing a context reference that deep into my code.
I saw here on StackOverflow about putting a reference to the SharedPreferences in my abc_123_object model, but there are quite a few objects I use (other than abc_123_object) and I don't want to have to jerry-rig so many classes.
So, is there a way for me to do this without modifying dozens of classes and passing context references all around my code, or am I stuck?
Thanks
Create static variable in your Application class.
public class MyApp extends Application{
public static Context context;
#Override
public void onCreate() {
context = this;
}
}
Then use it when you need.
public static String packageMe(Object input){
// do stuff here
// need SharedPreferences here
// context = MyApp.context
}
As Dusan mentioned, using an application class is an easy way to do this:
In your application class:
private static MyApplication sInstance = null;
private SharedPreferences mPrefs
public static MyApplication getApp()
{
return sInstance;
}
public SharedPreferences getSharePreferences()
{
return mPrefs;
}
in onCreate():
sInstance = this;
mPrefs = getSharedPreferences(PREF_FILE, MODE_PRIVATE);
Then in your code simply do:
MyApplication.getApp().getSharePreferences();
Your Application's onCreate() is guaranteed to be executed before any activity is created, so unless you are doing something really weird, it should be safe.

Extracting functionality to a separated class file is not working

I'm a noobie in OOP and Android, I'm facing a little problem that is frustrating me so much.
I'm creating an app that uses permanent storage.
Initially I created the code that access the saved preferences all mixed into the MainActivity, that worked, then I wanted to move that code to a separated class file.
The problem is that for some reason it won't work in a separated class file and after trying and trying I found that I could create an inner class inside the MainActivity class and that way it works.
I believe that it is related to the fact that if I create it as an inner class I don't need to make the inner class to extend Activity (again).
When creating an external class for the permanent storage handling, I needed to extend Activity on that class and I think that is the problem but I'm not sure.
Can somebody please explain to me why this is happening and maybe suggest the correct approach?
following I'm including a code snippet that works, but my goal is being able to create the class PermanentStorageHelper in a separated class file.
Thanks in advance!
public class MainActivity extends Activity {
public static MainActivity _mainActivity;
private TextView textView1;
// OnCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Persistent preferences
PermanentStorageHelper ps = new PermanentStorageHelper();
// UI Initialization
textView1 = (TextView) findViewById(R.id.textView1);
String uId = ps.getuId();
UiHelper.displayOnTextView(this, R.id.textView1, uId);
}
// =============================================
// This is the class I'm talking about, I'm unable to move this to
// a separated class (.java) file.
// It seems to be related to the fact that, if making this a separated
// class file, I need to extend Activity again and that is what
// seems to be the problem
// =============================================
public class PermanentStorageHelper /*extends Activity*/{
// CONSTANTS
public static final String USERUNIQUEID="userUniqueID"; // Saved setting 1
public static final String FILENAME="mtcPreferences"; // Filename for persisting storage file
// Fields
public SharedPreferences shp; // SharedPreferences field (1)
public String uId;
public PermanentStorageHelper(){
// Preferences initialization (2)
shp = getSharedPreferences(FILENAME, MODE_PRIVATE);
// Read Preferences (3)
uId = shp.getString(USERUNIQUEID, null);
}
// Getters and Setters
public String getuId() {
return uId;
}
public void setuId(String uId) {
this.uId = uId;
}
}
pass a context to your new class:
public PermanentStorageHelper(Context context){
// Preferences initialization (2)
shp = context.getSharedPreferences(FILENAME, MODE_PRIVATE);
}
Then you can create your class like:
new PermanentStorageHelper(MainActivity.this)
for getSharedPreferences you need to have access to the activity or applicationContext
You can add context to your constructor and use it to call getSharedPreferences:
public PermanentStorageHelper(Context context){
// Preferences initialization (2)
shp = context.getSharedPreferences(FILENAME, MODE_PRIVATE);
// Read Preferences (3)
uId = shp.getString(USERUNIQUEID, null);
}
in which case you would need to pass it on when creating the instance of the object:
PermanentStorageHelper ps = new PermanentStorageHelper(getApplicationContext());
or
PermanentStorageHelper ps = new PermanentStorageHelper(MainActivity.this);

Android - Global variables?

I need to stock some datas in my application.
I know that i can do it like this:
class:
public class MyApplication extends Application {
private String someVariable;
public String getSomeVariable() {
return someVariable;
}
public void setSomeVariable(String someVariable) {
this.someVariable = someVariable;
}
}
Implementation:
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getSomeVariable();
This is working if i'm in an activity.
But if i'm in a class not extended from Activity, how can I access at my datas?
thanks in advance for your help!
You can use a Singleton design pattern. You can then use it anywhere, because it has static access.
public class SingletonClass {
private static SingletonClass _instance = null;
private int _value = 0;
private SingletonClass() {
}
public static SingletonClass getInstance() {
if (_instance == null)
_instance = new SingletonClass();
return _instance;
}
public int getValue() {
return _value;
}
public void setValue(int value) {
_value = value;
}
}
and then access it like this:
SingletonClass.getInstance().getValue();
Note: This is a good and easy workaround for some programming problems, but use it very wisely.. it comes with it's problems
Use SharedPrefrences
http://developer.android.com/guide/topics/data/data-storage.html
Perhaps by injecting all the required for a class data via constructor or special setter, I would suggest former one. (Constructor Injection vs. Setter Injection)
There are more solutions like static fields but personally I do not like this approach since statics sometimes makes unit testing a bit messy.
BTW, what kind of variables you want to share?
I use, it may be gruesome to some, a class with static variables, that you can retrieve from every class in the app.
Just create a class with all the field as static, and you can use them throughout your app. It doesn't get erased, only when stopping the app.
You could also just add static variables to your application class.
You can use static methods (or variables if they are public). It's really a little messy, but if you group them (methods) in the right way you'll earn happinnes and satisfaction )
static public int getSomeInt(){
//something
}
And then anywhere in your app use
int x=MyApplication.getSomeInt();
By the way, using this style, you don't need to extend Application class. It's better to create an abstract class for such purposes.
Pass the context of your activity as a param to the method or class:
// ...
public void doStuff(Context context) {
// for example, to retrieve and EditText
EditText et = context.findViewById(R.id.editText1);
}
then, on your activity, you would do:
// ...
MyClass myClass = new MyClass();
// ...
myClass.doStuff(this);
// ...

Categories

Resources