Are Android Context objects serializable? - android

I declared a non-final static SharedPreferences object called PREFS together with the other constants in my Constants.java class:
public static SharedPreferences PREFS = null;
My reason for doing so is that my app is comprised of about 6 different AsyncTasks that keep accessing the same shared prefs file, and I didn't want to get the SharedPreferences and its Editor every time. On my app's first run, I make a call to getSharedPreferences() in my MainActivity and store it to PREFS so that it points to an instance before the AsyncTasks are fired, and therefore avoid a NullPointerException.
However, I kept getting NullPointerExceptions from the AsyncTasks anyway. All stack traces point to the line where I make a call to Constants.PREFS to get a value. My theory is that after some time, Android kills my app's process, so the next time the alarm for any of my AsyncTasks goes off, the value of Constants.PREFS would already be null.
My question is: Should I make a static variable for Context instead? Will its state be persisted even when Android kills off my process? I always pass a reference of Context to my AsyncTasks when the latter are instantiated so they can call on getSystemService(), and that never throws a NullPointerException. However, I don't see Context extending Serializable from the Android docs.

Use Application class to share preferences globally across the application.
public class MyApp extends Application {
private static Context mAppContext;
#Override
public void onCreate() {
super.onCreate();
mAppContext = getApplicationContext();
}
public static SharedPreferences getPreferences(){
return mAppContext.getSharedPreferences("my_app_preferences",MODE_MULTI_PROCESS);
}
}
Tell android you want your custom Application class, by mentioning it in the manifest:
<application android:name=".MyApp" android:label="#string/app_name" android:icon="#drawable/ic_launcher">
Now from anywhere, just call
MyApp.getPreferences().edit().putBoolean("pref1",true). . . put more stuff . .commit()
MODE_MULTI_PROCESS ensures all AsyncTask threads get synchronized access to same instance of SharedPreferences. Also, commit() is atomic, and will persist changes to the disk.
The above pattern is also handy for accessing resources from anywhere.
Update
It seems that static reference to context causes troubles with new Instant Run feature.
Hence, the context can be required as a parameter of utility method:
public static SharedPreferences getPreferences(context){
return context.getSharedPreferences("my_app_preferences",MODE_MULTI_PROCESS);
}

Related

Saving a static Context variable in Application class

I've wondering if it's okay to do this: whenever we pass a Context variable around, could we just get a singleton reference from the Application class instead
For example here is a subclass of Application class with a single static variable pointing to its own instance
public class App extends Application {
public static mApp;
#Override
public void onCreate(){
mApp = this;
}
}
Then when we need to pass a Context to a method from somewhere, can we just do
foo(App.mApp);
Isn't it okay to treat Context as an application variable?
Well it depends on the context in which you are using it. Many times a context is meant to keep hold of things until it's lifescope is complete and then allow garbage collection to take back whatever it was owning.
Other times the context needs to be an activity to handle life cycle call backs such as onNewIntent or onActivityResult.
Keeping a static instance in the parent is just a shortcut to avoid having to getApplication() and cast it as your type of application. I typically make a method for MyApplication.getApplication().doSomething which will return it's own reference of itself as opposed to ((MyApplication)getApplication()).doSomething
Just seems cleaner for coding purposes. But I would be very leary of using the application context everywhere you need a context, it will come back to bite you eventually.
But yes you can certainly store yourself as a static variable to be shared, I do it in most applications, but typically for a specific shortcut purpose of clean maintainable code, not for cheating on getting context from various crevices.

Why extend the Android Application class?

An extended Application class can declare global variables. Are there other reasons?
Introduction:
If we consider an apk file in our mobile, it is comprised of
multiple useful blocks such as, Activitys, Services and
others.
These components do not communicate with each other regularly and
not forget they have their own life cycle. which indicate that
they may be active at one time and inactive the other moment.
Requirements:
Sometimes we may require a scenario where we need to access a
variable and its states across the entire Application regardless of
the Activity the user is using,
An example is that a user might need to access a variable that holds his
personnel information (e.g. name) that has to be accessed across the
Application,
We can use SQLite but creating a Cursor and closing it again and
again is not good on performance,
We could use Intents to pass the data but it's clumsy and activity
itself may not exist at a certain scenario depending on the memory-availability.
Uses of Application Class:
Access to variables across the Application,
You can use the Application to start certain things like analytics
etc. since the application class is started before Activitys or
Servicess are being run,
There is an overridden method called onConfigurationChanged() that is
triggered when the application configuration is changed (horizontal
to vertical & vice-versa),
There is also an event called onLowMemory() that is triggered when
the Android device is low on memory.
Application class is the object that has the full lifecycle of your application. It is your highest layer as an application. example possible usages:
You can add what you need when the application is started by overriding onCreate in the Application class.
store global variables that jump from Activity to Activity. Like Asynctask.
etc
Sometimes you want to store data, like global variables which need to be accessed from multiple Activities - sometimes everywhere within the application. In this case, the Application object will help you.
For example, if you want to get the basic authentication data for each http request, you can implement the methods for authentication data in the application object.
After this,you can get the username and password in any of the activities like this:
MyApplication mApplication = (MyApplication)getApplicationContext();
String username = mApplication.getUsername();
String password = mApplication.getPassword();
And finally, do remember to use the Application object as a singleton object:
public class MyApplication extends Application {
private static MyApplication singleton;
public MyApplication getInstance(){
return singleton;
}
#Override
public void onCreate() {
super.onCreate();
singleton = this;
}
}
For more information, please Click Application Class
Offhand, I can't think of a real scenario in which extending Application is either preferable to another approach or necessary to accomplish something. If you have an expensive, frequently used object you can initialize it in an IntentService when you detect that the object isn't currently present. Application itself runs on the UI thread, while IntentService runs on its own thread.
I prefer to pass data from Activity to Activity with explicit Intents, or use SharedPreferences. There are also ways to pass data from a Fragment to its parent Activity using interfaces.
The Application class is a singleton that you can access from any activity or anywhere else you have a Context object.
You also get a little bit of lifecycle.
You could use the Application's onCreate method to instantiate expensive, but frequently used objects like an analytics helper. Then you can access and use those objects everywhere.
Best use of application class.
Example: Suppose you need to restart your alarm manager on boot completed.
public class BaseJuiceApplication extends Application implements BootListener {
public static BaseJuiceApplication instance = null;
public static Context getInstance() {
if (null == instance) {
instance = new BaseJuiceApplication();
}
return instance;
}
#Override
public void onCreate() {
super.onCreate();
}
#Override
public void onBootCompleted(Context context, Intent intent) {
new PushService().scheduleService(getInstance());
//startToNotify(context);
}
Not an answer but an observation: keep in mind that the data in the extended application object should not be tied to an instance of an activity, as it is possible that you have two instances of the same activity running at the same time (one in the foreground and one not being visible).
For example, you start your activity normally through the launcher, then "minimize" it. You then start another app (ie Tasker) which starts another instance of your activitiy, for example in order to create a shortcut, because your app supports android.intent.action.CREATE_SHORTCUT. If the shortcut is then created and this shortcut-creating invocation of the activity modified the data the application object, then the activity running in the background will start to use this modified application object once it is brought back to the foreground.
I see that this question is missing an answer. I extend Application because I use Bill Pugh Singleton implementation (see reference) and some of my singletons need context. The Application class looks like this:
public class MyApplication extends Application {
private static final String TAG = MyApplication.class.getSimpleName();
private static MyApplication sInstance;
#Contract(pure = true)
#Nullable
public static Context getAppContext() {
return sInstance;
}
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate() called");
sInstance = this;
}
}
And the singletons look like this:
public class DataManager {
private static final String TAG = DataManager.class.getSimpleName();
#Contract(pure = true)
public static DataManager getInstance() {
return InstanceHolder.INSTANCE;
}
private DataManager() {
doStuffRequiringContext(MyApplication.getAppContext());
}
private static final class InstanceHolder {
#SuppressLint("StaticFieldLeak")
private static final DataManager INSTANCE = new DataManager();
}
}
This way I don't need to have a context every time I'm using a singleton and get lazy synchronized initialization with minimal amount of code.
Tip: updating Android Studio singleton template saves a lot of time.
I think you can use the Application class for many things, but they are all tied to your need to do some stuff BEFORE any of your Activities or Services are started.
For instance, in my application I use custom fonts. Instead of calling
Typeface.createFromAsset()
from every Activity to get references for my fonts from the Assets folder (this is bad because it will result in memory leak as you are keeping a reference to assets every time you call that method), I do this from the onCreate() method in my Application class:
private App appInstance;
Typeface quickSandRegular;
...
public void onCreate() {
super.onCreate();
appInstance = this;
quicksandRegular = Typeface.createFromAsset(getApplicationContext().getAssets(),
"fonts/Quicksand-Regular.otf");
...
}
Now, I also have a method defined like this:
public static App getAppInstance() {
return appInstance;
}
and this:
public Typeface getQuickSandRegular() {
return quicksandRegular;
}
So, from anywhere in my application, all I have to do is:
App.getAppInstance().getQuickSandRegular()
Another use for the Application class for me is to check if the device is connected to the Internet BEFORE activities and services that require a connection actually start and take necessary action.
Source: https://github.com/codepath/android_guides/wiki/Understanding-the-Android-Application-Class
In many apps, there's no need to work with an application class directly. However, there are a few acceptable uses of a custom application class:
Specialized tasks that need to run before the creation of your first activity
Global initialization that needs to be shared across all components (crash reporting, persistence)
Static methods for easy access to static immutable data such as a shared network client object
You should never store mutable instance data inside the Application object because if you assume that your data will stay there, your application will inevitably crash at some point with a NullPointerException. The application object is not guaranteed to stay in memory forever, it will get killed. Contrary to popular belief, the app won’t be restarted from scratch. Android will create a new Application object and start the activity where the user was before to give the illusion that the application was never killed in the first place.
To add onto the other answers that state that you might wish store variables in the application scope, for any long-running threads or other objects that need binding to your application where you are NOT using an activity (application is not an activity).. such as not being able to request a binded service.. then binding to the application instance is preferred. The only obvious warning with this approach is that the objects live for as long as the application is alive, so more implicit control over memory is required else you'll encounter memory-related problems like leaks.
Something else you may find useful is that in the order of operations, the application starts first before any activities. In this timeframe, you can prepare any necessary housekeeping that would occur before your first activity if you so desired.
2018-10-19 11:31:55.246 8643-8643/: application created
2018-10-19 11:31:55.630 8643-8643/: activity created
You can access variables to any class without creating objects, if its extended by Application. They can be called globally and their state is maintained till application is not killed.
The use of extending application just make your application sure for any kind of operation that you want throughout your application running period. Now it may be any kind of variables and suppose if you want to fetch some data from server then you can put your asynctask in application so it will fetch each time and continuously, so that you will get a updated data automatically.. Use this link for more knowledge....
http://www.intridea.com/blog/2011/5/24/how-to-use-application-object-of-android

SharedPreferences application context vs activity context

I am using several SharedPreferences to store data in my app.
Some preferences are used in a lot of activites.
I know that the SharedPreferences are internally backed by a map for fast read-access and written to sdcard when settings are changed.
I wonder which way is better if a sharedpreference is accessed by a lot of activies:
Instantiate it in every activity using the activity context.
Instantiate it in every activity, but using the application context.
Put it in e.g. the Application class and instantiate it only once there, similar to a singleton.
If I use 1. solution is there a sharedpreference object for every activity? And will the sharedpreference's internal map get destroyed when the activity is destroyed?
If I use 2. solution will there be only one instance although I call getSharedPreferences in every activity? And will the internal map be in memory as long as the application is alive?
Hopefully someone knows how Android handles it internally.
It is worth reviewing the sources that show that a Context instance (be it an Activity or an Application instance) share the same static map HashMap<String, SharedPreferencesImpl>.
So whenever you request an instance of SharedPreferences by the same name via Context.getSharedPreferences(name, mode) you get the same instance since it first checks if the map already contains SharedPreferences instance for a key (which is the passed name). Once SharedPreferences instance is loaded it will not be loaded again, but taken from the map instead.
So it actually does not matter which way you go, the important thing is to use the same name in order to get the same prefs from different parts of the application. However creating a single "access point" for the prefs could be a plus. So it could be a singleton wrapper over the prefs instantiated in Application.onCreate().
SharedPreferences are managed internally by Android as singletons. You can get as many instances as you want using:
context.getSharedPreferences(name, mode);
as long as you use the same name, you'll always get the same instance. Therefore there are no concurrency problems.
I will prefer using a singleton class for preference, initialize preference once by application context. create getter and setter(get/put) methods to add, update and delete data.
This way it will create instance once and can be more readable,reusable.
We can make a Preferences Singleton Class and make instance of that class in extended Application class with applicationContext, so we may use that object in whole application
I have made a sharedPreferenceManager Class and make a static object by providing applicationContext. Now static object can be accessible anywhere in project
public class App extends Application {
public static App myApp;
public static PreferenceManagerSignlton preferenceManagerSingleton;
#Override
public void onCreate() {
super.onCreate();
myApp = this;
preferenceManagerSingleton = new PreferenceManagerSignlton();
preferenceSingleton.initialize(getApplicationContext());
}
}
Accessing static object in project
App.myapp.PreferenceManagerSignltonz.getSavedValue();

getApplication() and spanning Activities within a given Applications

I've spent a while reading up on this and have yet to find an answer.
I have a few activities all within one app. I'd like to share some data between them that is not suitable for intents or serialized data files. I know I can use the overall Application for this purpose, but I'm not fully understanding how it works.
We'll call my overall application class "MyApplication" and the main activity "MyActivity". I would expect that once the app begins from a cold start, it first instantiates and initializes MyApplication (calling onCreate()) and then goes on to instantiate and start my activity (MyActivity) (which was marked with the intent android.intent.action.MAIN). The logs seem to bear this out.
But... if I try to set the following Activity-wide variable, it gets set to null:
private final MyApplication THISAPP = (MyApplication)getApplication();
This is peculiar because the application definitely exists at this point. (Also, I can't delay setting a final variable til MyActivity.onCreate() gets called - that's disallowed ("The final field...cannot be assigned")).
Note that this works if I don't call THISAPP "final" and I assign it in onCreate(). That of course defeats the purpose of protecting a variable with "final" though, and it seems like it should be possible to do.
So, why isn't getApplication() producing a non-null value before onCreate()? Or is this some strange matter of context? (I've found a vague reference to context not being valid til after onCreate() is done, but would that apply to the parent Application's context as seen from a child Activity? I'd expect the parent to already have that set at that point.)
Edit: to emphasize, I can get this to work if I don't try to use final and if I remember to put the "." before the application name in the manifest (a mistake I made and corrected well-before this I wrote this question). It just isn't clear why getApplication() (or getApplicationContext() for that matter) aren't usable before onCreate() in a child Activity... unless "that's just how it is".
I'd like to share some data between them that is not suitable for intents or serialized data files. I know I can use the overall Application for this purpose, but I'm not fully understanding how it works.
I'd just use static data members as a cache for your persistent store, rather than fussing around with Application. Application gives you little advantage over static data members and has one big cost: there can only be one Application, whereas you can organize your static data members/singletons however you like.
I would expect that once the app begins from a cold start, it first instantiates and initializes MyApplication (calling onCreate()) and then goes on to instantiate and start my activity (MyActivity) (which was marked with the intent android.intent.action.MAIN). The logs seem to bear this out.
Correct.
But... if I try to set the following Activity-wide variable, it gets set to null: private final MyApplication THISAPP = (MyApplication)getApplication();
Of course. The activity object has not yet been initialized. You are welcome to use initializers like this for constants or things you get from static methods (e.g., Calendar.getInstance()) or other constructors (e.g., new ArrayList<Foo>()). Do not call a superclass method an expect it to work at this point, since the constructor chain has not yet been called on the object being instantiated. This is just Java, nothing particular to Android.
Have you done it the following way?
Created a class that implements Application
public class MySuperApplication extends Application
{
public String SomeSetting;
}
Defined which is your Application class in manifest (important!)
<application android:name=".MySuperApplication" android:icon="#drawable/icon"
and then accessed it in your activities
app = (MySuperApplication) getApplication();
app.SomeSetting = "Test";
This should work. It does in my case.
AFAIK, You cannot declare a empty final variable and initialize it onCreate. In java it is initialized during declaring the variable or in the constructor.
THISAPP cannot be initialized to Application object during declaration because the Application doesn't exist during compile time. Because onCreate is not a constructor, you cannot declare a empty final variable and initialize it in onCreate.
Instance variables are created when the object (in this case an Activity object) is constructed. For getApplication() to produce a valid value then the Activity object would have to have been provided enough context (little 'c') at instantiation for this to occur.
The source for getApplication() in Activity.java is just this:
/** Return the application that owns this activity. */
public final Application getApplication() {
return mApplication;
}
Here is where it is set:
final void attach(Context context, ActivityThread aThread, Instrumentation instr, IBinder token,
Application application, Intent intent, ActivityInfo info, CharSequence title,
Activity parent, String id, Object lastNonConfigurationInstance,
Configuration config) {
// other code
mApplication = application;
// other code
}
Since mApplication is not set until after attach is called, it won't be available to getApplication() on instantiation of your Activity.

Using objects obtained through android Context after the context is invalid

I have been working with android for a little while now and feel pretty comfortable with the platform, but I have gotten a little confused with the Lifecycle of Context Objects. Looking at the hierarchy it is easy to see that Activity and Service both extend Context, and while this is convenient, it is concerning. I have avoided making helper classes that need a shared resource have a static field holding a context (since just about all resources come through some interaction with a Context object) so that way when an activity is destroyed, the GC is free to free it at any time, but I am wondering about resources fetched from a Context.
For example, if I have a static field that holds a File inside of a class. Then make this class's constructor take the current context and assign the File a File resource fetched through the Context passed in, the do nothing else with the Context in my 2ndary class, am I still holding on in some way to the Context?
class testClass{
private static File someFile;
public testClass(Context context){
synchronized(testClass.class){
if(someFile!=null){
//even though I am holding a File, or a SharedPreference Object generated from this context, am I correctly preventing this utility class from holding the Activity object in memory for no reason?
someFile = context.openFileOutput("Some_File.txt", Context.MODE_PRIVATE);
}
}
}
}
I did just read about Context.getApplicationContext() (Sadly not static). It says it returns a context relative to the process and not the activity so if I need to keep a context around, use that one. But the question above still remains.
I remembered I asked this question and thought I would answer it.
Though there may be more kinds of contexts, the primary ones developers use are the Activity Context, and the Application Context (and other things like Service Context). The Activity context is created and destroyed with the activity, so it is not a good idea to use as a constant reference stored between activity creation and destruction. The Application Context doesn't have some of the things an Activity Context has, but everything you would want a static context reference for is there (file IO, preferences...). The application context is also created and destroyed with the application, so you can guarantee that as long as your application code is running, the context is valid.
Because of this, the Application context should be used for things like worker threads that may need a constant access point to a context but not need access to an activity. The best way I have learned to do this is to extend the android Application class. This class is created when the application is created in memory, and as soon as the Application onCreate method is called, the Application Context is valid. This means you can create a static function in your custom application class that gives access to the context.
public class CustomApplication extends Application {
private static Context context;
public void onCreate() {
super.onCreate();
context = getApplicationContext();
}
public Context getAppContext() {
return context;
};
}
The only other thing you need to make this work is a modification to your manifest file so android knows to use your application class instead of the default.
<application
android:icon="#drawable/icon"
android:label="#string/app_name"
android:name=".CustomApplication" >

Categories

Resources