Android - Global variables? - android

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);
// ...

Related

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.

Public Methods for all activities

I have a class called myConstants and in it i list all my constants so when i need them I just reference MyConstants.MYCONSTANT. However, i would like to implement something like this for methods. i am repeating a lot of code, for instance, i have a formatCalendarString(Calendar c) method in 3 activities. seems redundant and unecessary. but i cant make them static because i get static calling non-static errors and the only other way i can think is to make a MyConstant object then call public functions off that object, like this...
MyConstants myConstants = new MyConstants();
myConstants.formatCalendarString(Calendar.getInstance());
is there some way i can just call the formatCalendarString() inside MyConstants class without generating an object?
You can use singleton pattern to cache instances. Keeping methods in something like parent activity does not make any sense (as primary role of activity is user interaction).
Example:
public class MyConstants {
private static MyConstants ourInstance;
private MyConstants() {
//private constructor to limit direct instantiation
}
public synchronized static MyConstants getInstance() {
//if null then only create instance
if (ourInstance ==null) {
ourInstance = new MyConstants();
}
//otherwise return cached instance
return ourInstance;
}
}
You just need a private constructor and public static method that would only generate instance if it is null.
Then, call MyConstants.getInstance().whateverMethod(). It will create only single instance.
However when using singleton, please keep memory leaks in mind. Do not pass activity context directly inside singletons.
If you want to have all methods in activities, you can put then in abstract class BaseActivity, which extends Activity, and then make your activities extends BaseActivity. However, if these methods doesn't correspond to something about activity, I suggest some Singleton or Util class
I agree with Pier Giorgio Misley. It's also good to add a private constructor, because you don't obviously want to instantiate an object.
Can't you just use a parent class? That way you can just inherit the methods and manage in one source. Then you don't have to use static functions then.
Edit: Like Tomasz Czura said, just extend the Class.
public class ParentClass {
public void commonMethod(){
}
}
public class OtherClass extends ParentClass{
}
You can use the Static keyword.
Static methods can be referenced from outside without istantiating the new object.
Just create a class:
public class MyClassContainingMethods{
public static String MyStaticMethod(){
return "I am static!";
}
}
Now call it like
String res = MyClassContainingStaticMethods.MyStaticMethod();
Hope this helps
NOTE
You CAN call non-static from static by doing something like this:
public static void First_function(Context context)
{
SMS sms = new SMS();
sms.Second_function(context);
}
public void Second_function(Context context)
{
Toast.makeText(context,"Hello",1).show(); // This i anable to display and cause crash
}
Example taken from here, you will obiouvsly have to fit it into your needs

Using Gson to deserialise Json into a singleton

I'm using Gson to deserialise Json into a model ApplicationModel. I want this Model to be a singleton so I can access it elsewhere in my application.
Now as Gson creates an instance of this class, I'm creating the singleton instance in a rather unconventional way. See below:
public class ApplicationModel {
private static ApplicationModel instance;
private GeneralVO general;
protected ApplicationModel() {
instance = this;
}
public static ApplicationModel getInstance() {
return instance;
}
public String getVersionDate() {
return general.getVersionDate();
}
}
This is the way I create it and then reuse it later in the application:
InputStreamReader reader = new InputStreamReader(is);
ApplicationModel model1 = new Gson().fromJson(reader,ApplicationModel.class);
Log.i("MYTAG", "InputStream1 = "+model1.toString());
Log.i("MYTAG", "Date: "+model1.getVersionDate());
ApplicationModel model2 = ApplicationModel.getInstance();
Log.i("MYTAG", "InputStream1 = "+model2.toString());
Log.i("MYTAG", "Date: "+model2.getVersionDate());
This works as the getInstance() returns the same model but somehow this just doesn't seem right.
My question is 'is this a good way of going about it or is there a better solution???'
EDIT
A much better way of doing singletons is to use an enum with one INSTANCE element.
See this post for an explanation
I suggest to instantiate your singleton instance on your Model, rather than instantiating it using constructor.
public class ApplicationModel {
private static ApplicationModel instance; //= new ApplicationModel();
//instantiating here is called an "Eagerly Instantiated"
private GeneralVO general;
private ApplicationModel() {
}
public static ApplicationModel getInstance() {
//instantiating here is called "Lazily Instantiated", using :
//if (instance==null) { --> Check whether 'instance' is instantiated, or null
// instance = new ApplicationModel(); --> Instantiate if null
//}
return instance; //return the single static instance
}
public String getVersionDate() {
return general.getVersionDate();
}
}
By setting the constructor to private, you prevent the object from being re-instantiated by another class, to use the object, you will have to call the object with ApplicationModel.getInstance().
So if you want to set values, call ApplicationModel.getInstance().setterMethod(value), Why this is useful? if you want to track the change, you will only need to track the setter method. If you used constructors, you will have to track the constructors too.
Example :
// To SET the value:
// instead of ApplicationModel model1 = new Gson().fromJson(reader,ApplicationModel.class);
ApplicationModel.getInstance.setValue(new Gson().fromJson(reader,ApplicationModel.class);
// To GET the value :
ApplicationModel.getInstance.getValue();
The "Eager Instantiation" vs "Lazy Instantiation" :
Eager Instantiation is useful if you want an easy way to deal with
Threads
Lazy Instantiation has better memory footprints
There's more than that, you can google it for more info, but I think this should be enough for you right now.
Hope this helps, and good luck ^^
Regards,
Reid

update Global Var From LocationListener

I have created a class which holds global vars:
public class GlobalVar extends Application{
private XData xData;
public XData getxData ()
{
return xData;
}
public void setXdata (XData Xdata)
{
this.xData = xData;
}
}
When I access this class using (GlobalVar)getApplicationContext() from the activities of my application its fine, but when I want to access it from another class (in this case its LocationListener), I cant use (GlobalVar)getApplicationContext()
How could I access the data?
You should implement the Singleton pattern on your GlobalVar class. And access them directly without getter/setter is recommended on android (read the performance guide).
You could also just make your xData variable static and than you can access it directly from everywhere.
By using:
Context.getApplicationContext()
You can call
GlobalVar gv = (GlobalVar) getApplication()
from any Activity in your code.
For more info refer to http://developer.android.com/reference/android/app/Activity.html#getApplication()

Using Application context everywhere?

In an Android app, is there anything wrong with the following approach:
public class MyApp extends android.app.Application {
private static MyApp instance;
public MyApp() {
instance = this;
}
public static Context getContext() {
return instance;
}
}
and pass it everywhere (e.g. SQLiteOpenHelper) where context is required (and not leaking of course)?
There are a couple of potential problems with this approach, though in a lot of circumstances (such as your example) it will work well.
In particular you should be careful when dealing with anything that deals with the GUI that requires a Context. For example, if you pass the application Context into the LayoutInflater you will get an Exception. Generally speaking, your approach is excellent: it's good practice to use an Activity's Context within that Activity, and the Application Context when passing a context beyond the scope of an Activity to avoid memory leaks.
Also, as an alternative to your pattern you can use the shortcut of calling getApplicationContext() on a Context object (such as an Activity) to get the Application Context.
In my experience this approach shouldn't be necessary. If you need the context for anything you can usually get it via a call to View.getContext() and using the Context obtained there you can call Context.getApplicationContext() to get the Application context. If you are trying to get the Application context this from an Activity you can always call Activity.getApplication() which should be able to be passed as the Context needed for a call to SQLiteOpenHelper().
Overall there doesn't seem to be a problem with your approach for this situation, but when dealing with Context just make sure you are not leaking memory anywhere as described on the official Google Android Developers blog.
Some people have asked: how can the singleton return a null pointer?
I'm answering that question. (I cannot answer in a comment because I need to post code.)
It may return null in between two events: (1) the class is loaded, and (2) the object of this class is created. Here's an example:
class X {
static X xinstance;
static Y yinstance = Y.yinstance;
X() {xinstance=this;}
}
class Y {
static X xinstance = X.xinstance;
static Y yinstance;
Y() {yinstance=this;}
}
public class A {
public static void main(String[] p) {
X x = new X();
Y y = new Y();
System.out.println("x:"+X.xinstance+" y:"+Y.yinstance);
System.out.println("x:"+Y.xinstance+" y:"+X.yinstance);
}
}
Let's run the code:
$ javac A.java
$ java A
x:X#a63599 y:Y#9036e
x:null y:null
The second line shows that Y.xinstance and X.yinstance are null; they are null because the variables X.xinstance ans Y.yinstance were read when they were null.
Can this be fixed? Yes,
class X {
static Y y = Y.getInstance();
static X theinstance;
static X getInstance() {if(theinstance==null) {theinstance = new X();} return theinstance;}
}
class Y {
static X x = X.getInstance();
static Y theinstance;
static Y getInstance() {if(theinstance==null) {theinstance = new Y();} return theinstance;}
}
public class A {
public static void main(String[] p) {
System.out.println("x:"+X.getInstance()+" y:"+Y.getInstance());
System.out.println("x:"+Y.x+" y:"+X.y);
}
}
and this code shows no anomaly:
$ javac A.java
$ java A
x:X#1c059f6 y:Y#152506e
x:X#1c059f6 y:Y#152506e
BUT this is not an option for the Android Application object: the programmer does not control the time when it is created.
Once again: the difference between the first example and the second one is that the second example creates an instance if the static pointer is null. But a programmer cannot create the Android application object before the system decides to do it.
UPDATE
One more puzzling example where initialized static fields happen to be null.
Main.java:
enum MyEnum {
FIRST,SECOND;
private static String prefix="<", suffix=">";
String myName;
MyEnum() {
myName = makeMyName();
}
String makeMyName() {
return prefix + name() + suffix;
}
String getMyName() {
return myName;
}
}
public class Main {
public static void main(String args[]) {
System.out.println("first: "+MyEnum.FIRST+" second: "+MyEnum.SECOND);
System.out.println("first: "+MyEnum.FIRST.makeMyName()+" second: "+MyEnum.SECOND.makeMyName());
System.out.println("first: "+MyEnum.FIRST.getMyName()+" second: "+MyEnum.SECOND.getMyName());
}
}
And you get:
$ javac Main.java
$ java Main
first: FIRST second: SECOND
first: <FIRST> second: <SECOND>
first: nullFIRSTnull second: nullSECONDnull
Note that you cannot move the static variable declaration one line upper, the code will not compile.
Application Class:
import android.app.Application;
import android.content.Context;
public class MyApplication extends Application {
private static Context mContext;
public void onCreate() {
super.onCreate();
mContext = getApplicationContext();
}
public static Context getAppContext() {
return mContext;
}
}
Declare the Application in the AndroidManifest:
<application android:name=".MyApplication"
...
/>
Usage:
MyApplication.getAppContext()
You are trying to create a wrapper to get Application Context and there is a possibility that it might return "null" pointer.
As per my understanding, I guess its better approach to call- any of the 2
Context.getApplicationContext() or Activity.getApplication().
It is a good approach. I use it myself as well. I would only suggest to override onCreate to set the singleton instead of using a constructor.
And since you mentioned SQLiteOpenHelper: In onCreate () you can open the database as well.
Personally I think the documentation got it wrong in saying that There is normally no need to subclass Application. I think the opposite is true: You should always subclass Application.
I would use Application Context to get a System Service in the constructor. This eases testing & benefits from composition
public class MyActivity extends Activity {
private final NotificationManager notificationManager;
public MyActivity() {
this(MyApp.getContext().getSystemService(NOTIFICATION_SERVICE));
}
public MyActivity(NotificationManager notificationManager) {
this.notificationManager = notificationManager;
}
// onCreate etc
}
Test class would then use the overloaded constructor.
Android would use the default constructor.
I like it, but I would suggest a singleton instead:
package com.mobidrone;
import android.app.Application;
import android.content.Context;
public class ApplicationContext extends Application
{
private static ApplicationContext instance = null;
private ApplicationContext()
{
instance = this;
}
public static Context getInstance()
{
if (null == instance)
{
instance = new ApplicationContext();
}
return instance;
}
}
I'm using the same approach, I suggest to write the singleton a little better:
public static MyApp getInstance() {
if (instance == null) {
synchronized (MyApp.class) {
if (instance == null) {
instance = new MyApp ();
}
}
}
return instance;
}
but I'm not using everywhere, I use getContext() and getApplicationContext() where I can do it!
I know the original question was posted 13 years ago, and this is the Kotlin version of getting context everywhere.
class MyApplication : Application() {
companion object {
#JvmStatic
private var instance: MyApplication? = null
#JvmStatic
public final fun getContext(): Context? {
return instance
}
}
override fun onCreate() {
instance = this
super.onCreate()
}
}

Categories

Resources