3

Simple question. Reviewing my code, I've noticed that I've got a lot of variables declared multiple times in my classes or methods...for example:

public Long dbInsertCheckin(final String Class) {
final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
...
}

And

public class SmashDataSource {
    final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    final SimpleDateFormat sdf = new SimpleDateFormat("EEEE");
    final SimpleDateFormat timeFormat = new SimpleDateFormat("HHmm");
...
}

this got me thinking that instead of declaring "dateformat", "sdf", or "timeformat" or others i use in multiple places, would it not make more sense for me to declare these globally in my application class, then refer to them wherever I wanted like

public class MyApp extends Application {
public final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    public final SimpleDateFormat sdf = new SimpleDateFormat("EEEE");
    public final SimpleDateFormat timeFormat = new SimpleDateFormat("HHmm");

and refer to them later in other classes as such:

MyApp.dateformat
Myapp.sdf

Would this be better from a performance/memory usage point of view? Is there any reason not to do this? To me, it would seem that having declared them multiple times would consume more memory, vs. a final declaration once.... but I don't know how the compiler does it's optimizations.

Evan R.
  • 1,139
  • 1
  • 22
  • 37

5 Answers5

3

There is nothing wrong with using global variables. Generally they are avoided to keep things flexible and encapsulated. But some design patterns like the Factory Pattern go well with static/global classes. It also avoids code duplication.

(However I might avoid using my Application class so my global fields are only used when needed, but that's an implementation detail.)

I would do something like this probably. It keeps things flexible while also putting things in one place so they are consistent across your app.

public class MyGlobals
{
    private static SimpleDateFormat dateFormat;


    public static SimpleDateFormat getDateFormat()
    {
        if(dateFormat== null)
        {
            dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        }
        return dateFormat;

    }
}

Then you can use this in other classes:

MyGlobals.getDateFormat();

====


Here's some info from the dev docs about it:

http://developer.android.com/guide/faq/framework.html#3

For sharing complex non-persistent user-defined objects for short duration, the following approaches are recommended:

Singleton class

You can take advantage of the fact that your application components run in the same process through the use of a singleton. This is a class that is designed to have only one instance. It has a static method with a name such as getInstance() that returns the instance; the first time this method is called, it creates the global instance. Because all callers get the same instance, they can use this as a point of interaction. For example activity A may retrieve the instance and call setValue(3); later activity B may retrieve the instance and call getValue() to retrieve the last set value.

A public static field/method

An alternate way to make data accessible across Activities/Services is to use public static fields and/or methods. You can access these static fields from any other class in your application. To share an object, the activity which creates your object sets a static field to point to this object and any other activity that wants to use this object just accesses this static field.

A HashMap of WeakReferences to Objects

You can also use a HashMap of WeakReferences to Objects with Long keys. When an activity wants to pass an object to another activity, it simply puts the object in the map and sends the key (which is a unique Long based on a counter or time stamp) to the recipient activity via intent extras. The recipient activity retrieves the object using this key.

Persistent Objects

Even while an application appears to continue running, the system may choose to kill its process and restart it later. If you have data that you need to persist from one activity invocation to the next, you need to represent that data as state that gets saved by an activity when it is informed that it might go away.

For sharing complex persistent user-defined objects, the following approaches are recommended:

Application Preferences
Files
contentProviders
SQLite DB

If the shared data needs to be retained across points where the application process can be killed, then place that data in persistent storage like Application Preferences, SQLite DB, Files or ContentProviders. Please refer to the Data Storage for further details on how to use these components.

pjco
  • 3,794
  • 22
  • 25
  • thanks for this, I ended up using the Globals example to help reduce all the duplicate code for SDF's in my various classes. I started reading up on Singleton's as I'm not familiar with the term, I have read some of that in the developer guide before, but as I'm still learning a lot of these things are foreign to me (such as singletons) – Evan R. Sep 26 '12 at 20:21
1

Yes, it's a good idea to define these in one place - not just because it's cleaner, but also because then it's much easier to change them on a global scale without going through your entire code base. Personally, I would go with something like this:

public static final LONG_DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

However, in this particular case you need to be careful, because SimpleDateFormat objects are not thread-safe. This means that, if you are going to share one instance across your entire application, there are some extra steps to take to avoid concurrency issues. See one of the following for more details:

SimpleDateFormat thread safety

Proving that SimpleDateFormat is not threadsafe

“Java DateFormat is not threadsafe” what does this leads to?

Community
  • 1
  • 1
andersschuller
  • 12,123
  • 2
  • 35
  • 33
1

It all boils down to what you need and your current context.

If you can afford a little refactoring, IMHO the best approach would be to create a context class that contains all this kind of variables. You can take adventage of your refactoring session and even move other configuration parameters to that class and have it as a Singleton:

public class MyApplicationContext {
    //Constants and other global variables (I'd make the strings global, rather than
    //The time formats in this case.
    public final String TIME_FORMAT = "HHmm";

    //Context variables (taken from your source of choice)
    private String someConfigurationPath = "...";

    //Getters & Setters
}
Fritz
  • 9,677
  • 4
  • 26
  • 48
1

Global variables can be an indicator of code smell.

Maybe it is possible to find a pattern in the different locations, where the same simple date format is used. This can be a chance to refactor the code and move all common parts into a single place, e.g. combined into a new method (like printDate(aDate)) instead of the multiple instantiations of SimpleDateFormat and further surronding duplicate code.

mmehl
  • 225
  • 1
  • 6
  • late, but as I've grown more comfortable with developing Android/Java, I finally realize this more as my code grows, I've been starting to refactor things to make it easier to read/follow, as well as making methods out of common tasks that get repeated more than a few times. Thank you for this – Evan R. Aug 01 '14 at 04:45
0

I would, it all depends on what will change, but if you have all your config variables as statics you can just change the date format in one place and all the others wont need to be changed.

Sometimes for things like date formats it is desirable to put the date string in the stings.xml file so that you can vary the date format on a per country/language basis.

siliconeagle
  • 6,869
  • 2
  • 26
  • 35