I'm part of an Android project that uses a global class that contains public static variables, like the example below:
public class Globals {
public static MyObject variable = "this is a test";
}
In the middle of using the application, this global variable's value will be changed let's say:
#Override
public void onCreate(Bundle savedInstanceState) {
Globals.variable = new MyObject(somethingHere);
}
And I came across using Headless Retained Fragments from these blog posts:
http://www.androiddesignpatterns.com/2013/04/retaining-objects-across-config-changes.html
http://www.vogella.com/tutorials/AndroidFragments/article.html#headlessfragments
Problem:
I need to have a reference of an initialized object all over the application.
Question:
which is better to implement, a good practice, and practical? Or is there another way I could store a reference of an object all over the application?
The global class has been used over the project, and works fine, but are there any downsides of this implementation?
are there any downsides of this implementation?
Memory leaks, depending on what you are storing there. Leaks are why static data members are considered poor form in classic Java, even if we tend to use them more in Android app development.
Also, this data needs to be considered a cache, one that has to be able to be lazy-created on first access. Your process can be terminated at any point (wiping out the static data member) and the user can return to any activity in your app (courtesy of the recent-tasks list). If you want this data to survive process termination, the most likely solution will be to persist it in a file, database, or SharedPreferences.
All that being said, a retained fragment is a per-activity solution, not a per-application solution, and so it is not a valid alternative for your scenario AFAICT.
Related
I'm working on an Android app that uses some background tasks (AsyncTasks) and I want to use best practices regarding data persistence across app lifecycle and tasks callbacks.
Up to now, I have a mix of practices regarding this:
1) I have some static fields in classes where AsyncTasks are used in the form of:
private static String str1;
private static String str2;
private static int int1;
...//=>no more than 6 static fields
2) I use a sinleton App instance with many getters/setters in the form of:
package xxx.xxx.xxx
import xxx.xxx.xxx
...
public class AppSettings {
private static AppSettings singleton;
private String _field1;
...//=>many fields
public void setField1(String field1) { _field1 = field1; }
public String getField1() { return _field1; }
...//=>many getters/setters
private AppSettings() {}
public AppSettings getInstance(){
if (instance== null) {
synchronized(AppSettings.class) {
if (instance == null)
instance = new AppSettings();
}
}
return instance;
}
}
I definitely know that abusing of static fields is not good at all, so I decided to replace them all, but I'm not completely sure if my second approach -having an application instance in a singleton with many getters/setters- is considered a good way to go, and in case not, I would like to know about better alternatives.
Thank you very much.
Edit 1: Just to clarify.
In order for you to understand more clearly what I use my AppSettings singleton class for I'll give you two examples:
1) I use it to store app setting/configuration values (that's why the name) to be available anywhere. For example, font color, font size, whatever.
2) I use it to store temporary data/values. For example, my main activity creates a small video in the backgroung using "VideoHelper" class and called through an AsyncTask, and as video generation process needs some parameters from main activity, I use AppSettings getters/setters to send them through.
Edit 2: Better explanation of everything.
Thanks to #a_local_nobody I realized my "case of use" was not so clear so I'll add a few things more.
My AppSettings is not being used to store user settings, I use SharedPreferences for that, but instead app default configuration parameters.
To give an example, I store activities background color (and this is just an example) so if in the future I change my mind and decide to use another background color this setting (and many more) are centralized there. It's like a "container" for many default app settings.
Regarding the use of getters and setters in this app singleton class, I think I'll foloww #a_local_nobody suggestion related to define some static variables in each class and use them as needed instead of having a bunch of unrelated getters/setters globally.
Anyway, all comments are welcome.
Well, you are talking about persisting data across app lifecycle which, in my mind, sounds like you're looking for a ViewModel:
The ViewModel class is designed to store and manage UI-related data in
a lifecycle conscious way. The ViewModel class allows data to survive
configuration changes such as screen rotations.
as well as:
The purpose of the ViewModel is to acquire and keep the information
that is necessary for an Activity or a Fragment. The Activity or the
Fragment should be able to observe changes in the ViewModel.
ViewModels form part of the MVVM design pattern, with loads of examples available online.
For more info, have a look at the documentation
on a side-note, perhaps you can have a look at the google sunflower project for some ideas on how to implement the new architecture components, which includes usages of ViewModels.
Also worth adding, is that what you've created with your AppSettings solution, is a big dependency. Various things will depend on this single object and it will be needed throughout your application, most likely. You might consider, instead of creating it like this, to rather use dependency injection with your options, for android, probably being either Dagger 2 or Koin for kotlin (if you ever swap over to kotlin) or perhaps your own form of dependency injection without having to use these frameworks.
Hope this helps
Edit based on feedback from OP:
I use it to store app setting/configuration values (that's why the
name) to be available anywhere. For example, font color, font size,
whatever.
this sounds like a better use case for Shared preferences, especially if these are settings defined by a user, otherwise you should be savings these into strings.xml etc. and making use of localization
I use it to store temporary data/values. For example, my main activity
creates a small video in the background using "VideoHelper" class and
called through an AsyncTask, and as video generation process needs
some parameters from main activity, I use AppSettings getters/setters
to send them through.
if you have a VideoHelper class, you might be better off either creating a Builder design pattern for this object, or having static variables for this helper to change its functionality as you need to, if these are variables for your VideoHelper, then they should be located with your VideoHelper.
Things which change together should usually stay together.
Your approach doesn't qualify as "best practices" in modern android development.
The recommended way of handling configuration changes is by using the new architecture component: ViewModel
It have the property of surviving the onDestroy triggered when a configuration change occurs.
Basically, you will need to move this AppSettings code to a ViewModel.
I am looking for how to share functions and data across multiple activities within a single application. I researched the daylights out of it and find some ideology war between overriding the extend for the application and doing a singleton, neither of which I can find examples sufficient to make me understand. Basically I want to share data and share functions. All activities need the same functions and data so this is not one activity sharing data with another activity. It is all activities needing to have access to the same functions and data.
What I want to know is what is the way to go and how do I do it. I need to see what I need to do in my 34 activities, what the class that is going to be common looks like, and what the Manifest entry needs to be. I also need to be sure the common data area will not be closed by the OS.
This is my first Android - Java program and now find my 15,000 line, 34 activity application needs some structure. I know, should have done things differently but the app works really well with two exceptions. One is that it is structurally a mess. Two is that the fact it is a mess is making it hard to fix one behavior I would like to fix.
This is a GPS based application for racing sailboats. It is timing critical and every activity basically runs a once a second loop inside the location manager onLocationChanged function. That part is fine and I do not want to put the GPS code in one place. The problem is that most activities need to filter the data so a lot of code is copied and pasted to the activities. The filter needs history so it needs to remember a state. There are other functions that are used by several activities so these have been copied as well. Think of a function that averages the last three GPS speed readings. It needs to save some history, do its thing, and give a result. All activities need to do the exact same thing. All this works but the problem is that the averaging starts over every time I switch activities because every activity has its own filter. That gives a glitch in the data that I need to get rid of. I need common place to save the data and hopefully a common place to run the filtering and other functions that are common. If every activity can call the filter function that is using common state data, there will be no glitch across activity changes.
I would appreciate some guidance.
Why you don't just make a Class with only static functions, passing needed Parameters? An example if you want to show an ErrorDialog
public class SharedHelper{
public static Dialog showErrorDialog(Context ctx, String message, String title, DialogInterface.OnClickListener okListener, DialogInterface.OnClickListener cancelListener){
AlertDialog.Builder builder = new AlertDialog.Builder(ctx);
builder.setMessage(message).setTitle(tilte);
if (okListener != null){
builder.setPositiveButton(R.string.button_positive, okListener);
}
if (cancelListener != null){
builder.setNegativeButton(R.string.button_negative, cancelListener);
}
return builder.show();
}
}
Singletons are (from my point of view) one of the uglyest design pattern and will bite you sooner or later. Putting anything in Application requires you to cast it everytime to the Special Application class you designed. A class with only statics however is very flexible in its usage and doesn't need an instance to work.
For the storage-issue:
lookup "SharedPreferences" & "SQLite" and decide afterwards which storage-type suits your needs more.
For the methods-issue:
This question is a bit more complex and there are different ways to do it. For example you could write a parent-class that implements all your globally needed questions and you let all your activity-classes inherit from it.
public class MyParentActivity extends Activity {
public void myMethod() {
}
}
and:
public class Activity1of34 extends MyParentActivity {
myMethod();
}
I think what this comes down to is not an Android problem but an Object-Oriented Programming problem. If I understand the situation correctly, I'm betting the best solution would be to take your shared filter and create a new Filter class that is instantiated within each Activity (this is likely more manageable than a singleton, but not having seen your use case, it's hard to say for sure). If you need to centrally track the averaging, you can simply create a static variable within the Filter class that maintains the same value during the life of the application. If you really want to maintain that average (even past the application's current lifecycle), you can persist it in a database or other local data options. However, I don't see any reason to put everything in a singleton just to maintain that average. Singletons (and all static data structures) can be potentially troublesome if used incorrectly.
I, for one, do not mind the singleton pattern. Of course as everything else it should not be abused.
This is the construction I use for my shared objects. My app is divided into modules this way but can just as well be used in your case.
public class SharedDataObject {
private Context context;
private static SharedDataObject instance;
public static SharedDataObject getInstance() {
if (instance == null) throw new RuntimeException("Reference to SharedDataObject was null");
return instance;
}
public static SharedDataObject createInstance(Context context) {
if (instance != null) {
return instance;
}
return instance = new SharedDataObject(context.getApplicationContext());
}
// notice the constructor is private
private SharedDataObject(Context context) {
this.context = context;
}
...
public void myMethod() {
// do stuff
}
}
Notice that it uses the application context, that means among other things, means that the context owned by SharedDataObject cannot be used for GUI operations. But, the context will live for the entire lifetime of the application, which is nice.
Furthermore I hate having to pass a context everytime I wish to call methods on my SharedDataObject, thus I have a splashscreen calling SharedDataObject.createInstance() on all my modules.
Once an instance is create, I can call:
SharedDataObject.getInstance().myMethod();
Anywhere in my code, regardless of a context being present or not (from the place calling this code that is).
Recently I have started development in Java for Android.
My idea is to create one static class which will load ton of stuff on the beginning and store results for a lifetime of application.
I have been reading lot of how to share object between activities and I think the best will be to create one static class. What do you think? Should I use another approach? I am asking because I have read lot of counter opinions over the internet.
Thank you.
I'm assuming that you were referring to static fields of a class, as opposed to static class which, as Wyzard pointed out, is something completely different. As a general rule of thumb, holding information in static fields is not a good idea in Java. The reason for this is that it prevents the ability to instantiate multiple instances of whatever it is you store in the class.
In the specific case of an Android application, the best way to deal with the issue of having data stored associated with the application itself is to subclass the android.app.Application class and use it to handle application-global data:
class FooApplication extends Application
{
private String privData;
public String getPrivData() {
return privData;
}
}
You then need to declare that this class is your main application class (instead of the default Application). In the application entry in AndroidManifest.xml add the following:
<application android:name="com.example.application.FooApplication"
...>
...
</application>
You can then look up the application instance from anywhere inside your application using the method Context.getApplicationContext() which will be an instance of your Application subclass:
FooApplication app = (FooApplication)Context.getApplicationContext();
String privData = app.getPrivData();
Depending on from where you are trying to look for subclass of "Application", you may have to invoke the "getApplicationContext()" without "Context":
FooApplication app = (FooApplication)getApplicationContext();
String privData = app.getPrivData();
The problem with your solution is that you're basically creating a huge stack of globals. It's sometimes unavoidable, but it has the same type of problems globals always have- you quickly end up with hard to read code that doesn't really have a good OO breakdown. You can use this, but use it sparingly- only with important data structures that are really going to be shared between many activities.
Android provides a class called Application, which is will not be gc'ed as long as your Application isn't killed. Use this class for initialization, static classes as containers are somewhat ugly, but i can't pinpoint why that is.
I only use them as containers for constants such as bitmasks which can't be expressed as EnumSets.
As the other posts mention SharedPreferences: I think the preferences exist to store values, but not to load your structures that you need for you application. These structures should be loaded from a construct that represent or make up a model for your data's semantics.
I'm trying to persist data objects throughout my Android app. I want to be able to access an object in one activity, modify it, save it, navigate to a new activity, and access the same object with the updated value.
What I'm essentially talking about is a cache, but my data objects are complex. For example, ObjectA contains ObjectB which contains ObjectC. Does anyone know if a good method, tool, or framework for persisting complex objects in Sql?
Put a static field in a subclassed Application. Also inside your manifest, put:
android:name="MyApp" inside your application tags.
Also to access from other files, simply use:
MyApp myApp = (MyApp)getApplicationContext();
See here How to declare global variables in Android?:
class MyApp extends Application {
private String myState;
public String getState(){
return myState;
}
public void setState(String s){
myState = s;
}
}
class Blah extends Activity {
#Override
public void onCreate(Bundle b){
...
MyApp appState = ((MyApp)getApplicationContext());
String state = appState.getState();
...
}
}
You could use an ORM framework, like OrmLite for mapping objects into sql, but it may be an overkill for you situation.
You could also make these shared object Parcelable and pass them between the Activities thru the Intents.
You could also save these objects into the SharedPreferences, so each Activity can access them whenever they feel the need to it, and the objects are also persisted this way. This may mean more IO access though, so take that into consideration as well. You could use e.g. Gson to serialize the objects more painlessly for this.
These are the solutions I'd consider. But whatever you do, don't put this common object into some kind of "standard" global static variable, like using a custom Application class, static field or any implementation of the Singleton pattern, these are really fragile constructs on Android.
Why don't you use a JSON serialization mechanism ?
In association with a static access to your objects you can easily build a lite-weight database with some basic functionnalities:
loadObjectsFromCache
saveObjectsInCache
getObjects
You can also store your objects in differents files, and use a streaming json parser like this one: http://code.google.com/p/google-gson/
It's the same that this one: http://developer.android.com/reference/android/util/JsonReader.html
but can be used even if your application api level is inferior to 11.
It use less memory than the basic DOM parser:
http://developer.android.com/reference/org/json/JSONObject.html,
but with the same speed.
There are many questions and answers on how to implement a global variable in Android/Java.
So it seems one can either implement a singleton or use a data class itself with static variables.
I am about to start a larger project and would like to start on the right foot.
I am just not sure which one to use.
Pro singleton/con Data Class
supposedly "cleaner" way (but I really don't know why)
ensures that there is really always just one representation
creates a new instance should the old one be "cleaned away" (whenever this may happen?)
Con singleton/pro Data Class
not recommendet by some (but did not find convincng reasons)
ensures that there is only one representation by design
very easy to access just by writing MyDataClass.x (vs accessing singleton requires getting access to it first somehow)
no need to pass it as a parameter
So in summary I tend to use DataClass but I am unsure because I read that this is supposedly not good programming style.
I like to add
the data this global object has to hold is quite big, more than 30k strings/keys. And this should not be cleaned at any stage so that when the app return it may crash because of that - as I read in other places eg Singletons vs. Application Context in Android? (the 3rd answer)
it's not a web application, I use only one classloader
it is multithread but only one thread is actually accessing this data
one may certainly also use this approach How to declare global variables in Android?, but isn't an ObjectClass just easier to use and access in this case?
And checking this http://developer.android.com/resources/faq/framework.html, esp under "Persistent Objects", implies that there is no real advantage for on or the other in those cases anyway.
Many thanks
Best way to implement singleton is to use enum.
public enum Singleton
{
INSTANCE;
public void someMethod()
{
// your code here
}
}
For more details you can read Effective Java (2nd Edition)
First of all: There's not much difference between a class with public static member variables and a singleton class. A lot of developers prefer the singleton pattern because the code looks more natural and more Java. E.g. Singleton.Data looks like a constant access and Singleton.getData() looks like you're accessing some kind of static data.
Personally I use the static Application pattern: See Accessing resources without an Activity or Context reference
You can use onCreate to setup any kind of static data or even other singletons. E.g. I prefer to setup a singleton SQLite database like that and access it then via App.getDb(). You can use this pattern to access the application context or resources.
While using static data you should think about memory leeks. I would recommend to take a look at this article then.