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);
Related
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.
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();
}
}
Hi I am doing one app here. I'm using global class varibles. It's working well, but if I'm using more globalclass variables I'm getting memory exceptions some times.
I tried this:
public class SecondClass extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second);
TextView tv = (TextView)findViewById(R.id.tv);
tv.setText("Global String : " + GlobalClass.myVal);
}
}
class GlobalClass extends Application {
static String myVal;
}
Is this correct or not?
First thing, you dont need Static Variable to declare global variable in Application Class,
so Change your code to:
class GlobalClass extends Application {
public String myVal;
}
then whereever you need to access this data, get Application object by:
GlobalClass global=(GlobalClass)context.getApplication();
global.myVal="anything";
You can use like this
public class GlobalVar {
public int getMyVar() {
return myVar;
}
public void setMyVar(int myVar) {
this.myVar = myVar;
}
private int myVar = 0;
private static GlobalVar instance;
static {
instance = new GlobalVar();
}
private GlobalVar() {
}
public static GlobalVar getInstance() {
return GlobalVar.instance;
}
}
then you can call like
GlobalVar.getInstance().setMyVar(int);
You can also use Global Variable Activity class wise. As for example
public class SecondClass extends Activity {
String S1,S2,S3;
EditText edt1,Edt2,Edt3;
Button btn1,btn2,btn3;
//like this wat Declare all variable you want to use in your Present Activity Class
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.second);
edt1= (EditText)findViewById(R.id.tv);
}
}
Take a look at the post Singletons vs. Application Context in Android?
There are a lot of discussion about Singletons vs Application objects in the forum.
I'm personally inclined to Application object with properties. If you dont want to keep in memory a lot of objects use a LruCache (there is a pre v11 implementation in the compatibility package) to low your memory requirements.
Take into account you will eat the same amount of memory using Singletons than using the Application object, all objects will be keep in memory until you free them (remove any refrence to them and let the GC purge them from memory).
In my application i want to maintain data without using the local DB even if the application closes. For this i created one class in my app, in that i created static variables so we can access them anywhere in the app. But here some times data is gone i don't know why it's happen. this process is good or any better is there? Somewhere i read that Shared Preferences is useful but i don't know about that.please can anyone share your ideas.
public class AJ_Constant {
//New Food Item
public static String strEntrySavedFoodItem = "";
public static String strReportsSavedFoodItem = "";
public static ArrayList<String> arrFoodItems = new ArrayList<String>();
}
public class ReportsContentActivity extends Activity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
View contentView = LayoutInflater.from(getParent()).inflate(R.layout.reports_content, null);
setContentView(contentView);
AJ_Constant.arrFoodItems.add("Sample"); }}
thanks
Visit http://android-er.blogspot.in/2011/01/example-of-using-sharedpreferencesedito.html
you can save your data by creating shared preferences.
you can have a look here. there are samples how to use SharedPreferences
I have some information stored as SharedPreferences. I need to access that information from outsite an Activity (in from a domain model class). So I created a static method in an Activity which I only use to get the shared preferences.
This is giving me some problems, since apparently it is not possible to call the method "getSharedPreferences" from a static method.
Here's the message eclipse is giving me:
Cannot make a static reference to the non-static method
getSharedPreferences(String, int) from the type ContextWrapper
I tried to work around this by using an Activity instance, like this:
public static SharedPreferences getSharedPreferences () {
Activity act = new Activity();
return act.getSharedPreferences("FILE", 0);
}
This code gives a null point exception.
Is there a work-around? Am I going into an android-code-smell by trying to do this?
Thanks in advance.
Cristian's answer is good, but if you want to be able to access your shared preferences from everywhere the right way would be:
Create a subclass of Application, e.g. public class MyApp extends Application {...
Set the android:name attribute of your <application> tag in the AndroidManifest.xml to point to your new class, e.g. android:name="MyApp" (so the class is recognized by Android)
In the onCreate() method of your app instance, save your context (e.g. this) to a static field named app and create a static method that returns this field, e.g. getApp(). You then can use this method later to get a context of your application and therefore get your shared preferences. :-)
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());
I had a similar problem and I solved it by simply passing the current context to the static function:
public static void LoadData(Context context)
{
SharedPreferences SaveData = context.getSharedPreferences(FILENAME, MODE_PRIVATE);
Variable = SaveData.getInt("Variable", 0);
Variable1 = SaveData.getInt("Variable1", 0);
Variable2 = SaveData.getInt("Variable2", 0);
}
Since you are calling from outside of an activity, you'll need to save the context:
public static Context context;
And inside OnCreate:
context = this;
Storing the context as a static variable, can cause problems because when the class is destroyed so are the static variables. This sometimes happens when the app is interrupted and becomes low on memory. Just make sure that the context is always set before you attempt to use it even when the class setting the context is randomly destroyed.
Here's a better alternative to storing your shared preferences in static fields.
Similar to what has been suggested here, create a class that extends Application
Make the constructor for your class take Context as a parameter.
Use your context to get shared preferences and store them in private variables.
Create public variables to return the retrieved data.
e.g
public class UserInfo extends Application{
private String SAVED_USERID;
private String SAVED_USERNAME;
public UserInfo(Context context) {
SharedPreferences prefs = context.getSharedPreferences(FILE, MODE_PRIVATE);
SAVED_USERNAME = prefs.getString("UserName", null);
SAVED_USERID = prefs.getString("UserID", null);
}
public String getSavedUserName() {
return SAVED_USERNAME;
}
public String getSavedUserID() {
return SAVED_USERID;
}
}
usage in your activity
UserInfo user = new UserInfo(this.getApplicationContext());
String SAVED_USERNAME = user.getSavedUserName();
String SAVED_USERID = user.getSavedUserID();
I had the same need - some of my preferences need to be accessed often, and efficiently. I also imagine that reading and writing a string from SharedPreferences is slightly slower than getting and setting a static variable (but likely to an insignificant degree). I also just kind of got used to using static fields, retrieving Preference values only at startup, and saving them on close.
I didn't love my options for keeping static references to the SharedPreferences/contexts directly, but so far this workaround has sufficed.
My solution:
Create a Settings class with all the static variables you need.
When the application initializes, retrieve SharedPreferences fields and immediately set all Settings fields (I call a "loadSharedPrefs()" method at the end of MainActivity's onCreate method).
In the SettingsActivity's preferenceChangeListener's initialization, set the appropriate static field in the Settings class. (I call a "setAppropriateSetting(key, value)" method at the beginning of SettingsActivity's onPreferenceChange()).
Use your static preferences wherever, whenever!
public static String getPreferenceValue(Context context) {
SharedPreferences sharedPreferences =
PreferenceManager.getDefaultSharedPreferences(context);
String key = context.getString(R.string.pref_key);
String defaultVal = context.getString(R.string.pref_default);
return sharedPreferences.getString(key,defaulVal);
}