Use of static member in Android Application bad? - android

I've stumpled upon an Android Application Class which implements the Singleton pattern and bind a static object to it.
public class App extends Application
{
public static BigObject myObj;
private static App instance;
public static App getInstance()
{
return instance;
}
#Override
public void onCreate() {
super.onCreate();
instance = this;
myObj = new BigObject(this);
}
}
Are there any problems with this implementation, regarding performance, memory leaks or maybe Exceptions, when getInstance().myObj.something() is called form BroadcastReceiver or Service?

The only drawback I see is somewhat ugly code, using dependency injection would be better. I don't know, but if OS guarantees that all other components will be launched after Application::onCreate than there is no issues. Even non-main threads will not cache value of bigObject. But if you want set value of bigObject after onCreate, or it's creation takes long time you can face issues with data racing or slow startup.

I don't see any problems with this implementation. The Application object is basically a singleton.

Related

Is it safe to bind Application context in its onCreate?

Let's assume we have a custom App extends Application.
I understand that wherever possible getApplicationContext() method should be used, but it's only applicable if you're within a scope that provides this method. Sometimes you need to access it outside of it and that's why I started wondering.
Here's the sample code
public class App extends Application
{
private static App instance = null;
public static App getInstance()
{
return instance;
}
public static Context getContext()
{
return instance;
}
#Override
public void onCreate()
{
instance = this;
super.onCreate();
}
}
Does App.getContext() return the same context getApplicationContext() would return in an appropriate scope? Is it safe to bind the App context like this?
Lifetime of statics is practically the same as your Application. It's safe in the sense that there won't be a memory leak and it will always refer to the correct Application.
getApplicationContext() returns the Application object which also is-a Context.
However, static data like this is a design smell you should try to avoid. It adds unnecessary coupling to your code, making components harder to test in isolation. Instead, consider passing a Context as a parameter where one is needed.
For a good article about what a particular kind of Context such as Application is good for, read http://www.doubleencore.com/2013/06/context/

android new activity can't load singleton

I am trying to use a Singleton to share a large data object between Activities. But when I open the new Activity, the singleton comes up as empty. It seems to me that the Singleton should be the same no matter where in the Application I call if from.
It seems like the Scope of the Singleton is being limited to the individual Activity. Working around this is making my App very complicated. I must be doing something wrong. I even tried instantiating them in an extended Application class... Google says I should not have to use that though...
Can someone please point out where I am going wrong? i.e. Why does this singletom not contain the same data in each Activity?
I call it from an Activity with...
DataLog dataLog = DataLog.getInstance(this);
I have...
public class DataLog extends ArrayList<String> implements Serializable {
private static final long serialVersionUID = 0L;
private static DataLog sInstance;
private static Context mContext;
public static DataLog getInstance(Context context) {
mContext = context.getApplicationContext();
prefs = PreferenceManager.getDefaultSharedPreferences(mContext);
if (sInstance == null) {
sInstance = new DataLog();
}
return sInstance;
}
private DataLog() {
}
public boolean add(String entry) {
super.add(entry);
return true;
}
public void add(int index, String entry) {
if (index > 0)
super.add(index, entry);
else
super.add(entry);
}
public void clear() {
super.clear();
}
...
}
Its highly advisable to avoid singleton for sharing large data sets in android.
Singletons are used for short life-cycle objects.
Switch to SharedPrefferences, SQLite DB's or file storing. You are not the only to have experienced this behavior, and the reason lies in the nature of android Activities and the system itself(managing activities and its data).
Here is an example why singleton is bad for your case:
You stored important data in it. The user knows that he can close the app on home button to call someone or whatever)maybe someone called him when he was in your app), and that when he opens your app he will come back at the same place with everything in order. (this is expected behavior from users and android apps). The system can easily kill your process and all static variables in it for memory maintenance, app inactivity etc...result=data lost. Thus its not safe to use it.

What version of RoboGuice works with Android SDK 8?

That's probably part one of my question.
Basically I'm struggling with the actual injection for version 1.1.2. I've read the couple of pages on the site, and I feel I'm missing something.
Basically I've done the RoboApplication extension. I've overridden the addApplicationModules method. I've even made a module.
My module looks like this:
public class DataRepository extends AbstractAndroidModule
{
#Override
protected void configure() {
/*
* This tells Guice that whenever it sees a dependency on a TransactionLog,
* it should satisfy the dependency using a DatabaseTransactionLog.
*/
bind(IDataBaseAdapter.class).to(DataBaseAdapter.class);
}
}
In my adapter I have this:
public class DataBaseAdapter implements IDataBaseAdapter
{
private DataBaseHelper _dbHelper;
private SQLiteDatabase _db;
#Inject
protected static Provider<Context> contextProvider;
public DataBaseAdapter()
{
_dbHelper = new DataBaseHelper(contextProvider.get());
}
}
If I don't do there, where is the opportune place for the chunk of code to reside... where I associate injectors?
Finally... my Application has an injection of it like so:
public class MyApplication extends RoboApplication
{
public MyApplication()
{
super();
}
public MyApplication(Context context)
{
super();
attachBaseContext(context);
}
#Override
protected void addApplicationModules(List<Module> modules)
{
modules.add(new DataRepository());
}
#Inject
private IDataBaseAdapter adapter;
public IDataBaseAdapter getAdapter()
{
return adapter;
}
public void setAdapter(IDataBaseAdapter value)
{
adapter = value;
}
...
}
I'm trying to use the Inject attribute as shown. For example:
#Inject
private IDataProvider provider;
A couple of reasons why I'm lost is that I come from a .NET and Flash/ActionScript background plus I've only used StructureMap instead of Ninject (in the .NET world), which I've heard Guice is designed with some of the ideas of Ninject in mind. Could someone help me figure out this small piece?
I'd really like to focus on using 1.1.2 instead of jumping to 2.x of RoboGuice... especially since it is still in beta, so I hope you all don't mind.
Thanks again,
Kelly
Android is quite different from standalone / hosted java application. You do not have main() , but you have certain activity units, which are managed by android framework (activities, services , broadcast receivers)
DI is a technique which allows you to eliminate booler plate code by wiring together
parts in good object oriented way.
As your unit of work is mostly activity, you shall do wiring / creation of your collaborating objects in onCreate() method , and there are dedicated onResume() and onPause() methods (see actviity lifecycle)
Rule of thumb is, does this thing needs to be restarted every time activity loses it focus? If yes, initialize / destroy it in inResume() / onPause(), otherwise - in onCreate()
And if you like to share objects withing entire application ( running in same JVM ) , it is OK to use singleton pattern in android. So you may just have singleton injector factory , and cosult it from everywhere:
InjectorFactory.getInstance(<context if necessary?>).getInstance(whatever you need);
OK, I've figured out what was needed, but I'm not quite sure why after seeing all the information floating out there.
I basically made this change, and now my test passes.
public class DataBaseAdapter implements IDataBaseAdapter
{
private DataBaseHelper _dbHelper;
private SQLiteDatabase _db;
#Inject
public DataBaseAdapter(Provider<Context> contextProvider)
{
_dbHelper = new DataBaseHelper(contextProvider.get());
}
}
While I like using constructors as the tool for injecting, I wonder why it had to work this way, considering that examples I have seen are some kind of reflection class injection.
Anyway, that's this part. Hopefully someone else will find this useful.
Cheers,
Kelly

Can I use an activity to initialize some objects then finish?

If I initialize some static objects in an activity and then call finish(), do those objects still exist elsewhere in the application? Like say I want to access them later on in a service.
If not, are there any other solutions where I could initialize some static objects one time that other classes will have access to?
Yes, doing that is possible. But for the static objects to continue to exist, there should be at least one Activity/Service in the application to be running. What I normally do for such variables is to create a class to hold static methods and variables. Something like this:
public class Utils
{
public static String s;
public static int i;
public static initStatics()
{
s = "";
i = 0;
}
}
This you can call from your other Activity/Service like this:
public class CustomService extends Service
{
#Override
public void onStart()
{
Utils.initStatics();
}
}
So, these variables will be available as long as your app is running. Hope that helped. Good luck!
For things of that nature you can use static member variables on the Application object. You will have to clean up manually (since onDestroy is never called), and you will need to make sure there is at least one Activity/Service in the application running to prevent the app's process from being destroyed by the OS.

Singleton wrapper for Context

I'm considering creating a singleton wrapper for a Context so my model objects, if necessary, can open and read from a database connection. My model objects do not have access to a Context, and I'd like to avoid needing to pass a reference to a Context from object to object.
I was planning to place into this singleton a reference to the Context returned by Application.getApplicationContext(). This singleton object would be initialized in my custom Application instance before anything else would need to or have a chance to use it.
Can anyone think of a reason to not do this?
I would urge you to think about what reasons you have for not passing a reference of the application context into your model objects.
There are various well-documented disadvantages of using singletons. I won't go into detail here but you might want to consider:
How singletons limit your ability to properly unit-test your application.
Singletons hide dependencies between different entities in the code- you cannot determine dependecies from inspecting the interfaces.
You have no real control over the lifetime of a singleton, it could exist for the lifetime of your application. Do you really want to potentially hold a DB connection for the lifetime of your app?
The thread safety of your singleton.
If you valid reasons for not passing a reference to a context to other parts of your application then perhaps you should consider some other pattern- a factory might be one possible solution, a service another.
I'm not sure I get your idea, but here's what's been working for me:
public class MyApp extends Application {
private static MyApp instance;
#Override
public void onCreate() {
super.onCreate();
instance = this;
// ...
}
public static MyApp getInstance(){
return instance;
}
// misc helper methods
}
Pasted here to preserve formatting.
public class ContextContainer
{
private static boolean initialized;
private static Context context;
private ContextContainer()
{
//
}
public static synchronized void setApplicationContext(Context context)
{
if (!initialized) {
ContextContainer.context = context;
initialized = true;
} else {
throw new RuntimeException("ApplicationContext has already been set!");
}
}
public static synchronized Context getApplicationContext()
{
return context;
}
}

Categories

Resources