I thought a singleton instance should not be garbage collected, however I maintained a singleton object, and mark it when it was initialized, like this:
private static LocalCache instance;
public LocalCache() {
// initialize objects......
}
public static LocalCache getInstance() {
if (instance == null) {
instance = new LocalCache();
Log.e("instance", "new");
}
return instance;
}
I found that this log appear more than once in my application.
More precisely, I have 5 fragments in a FragmentActivity. When I press home button to do some task and switch back to the activity, the singleton class seems to be reallocated. Is there thing wrong in my code? Or can I prevent the fragment being recreated?
I'm sure I didn't assign null to the instance.
#Override
protected void finalize() throws Throwable {
Log.e("finalize", "finalize");
}
I also override finalize() to observe when it was destroyed, but the log didn't appear before the second "new instance" log.
Is there thing wrong in my code?
Usually, for a singleton, you use synchronized and volatile for locking, to make sure that you do not allocate multiple instances due to parallel calls on multiple threads. Or, in your case, just use a static initializer, since your getInstance() does not take any parameters needed to instantiate your LocalCache.
However, more likely, the issue here is that your process was terminated. Once you are no longer in the foreground, your process can be terminated at any point. When your app runs again, a new process is created, and all static data members will initially be null.
Related
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.
I see that if one instantiates a Dagger 2 Component in an Activity, then it's later nulled in the onDestroy() method like seen here.
public class MyActivity {
private MyActivityComponent component;
//...
public void onCreate() {
component = Dagger_MyActivityComponent.builder()
.myApplicationComponent(App.getComponent())
.build()
.inject(this);
//...
}
public void onDestroy() {
component = null;
}
}
What happens if I don't null that instance and what would happen?
Side note: in comments I've found useful hint why one would set it to null which is pretty convincing: "I don't think it's necessary but it defines scope pretty clear".
What happens if I don't null that instance [...]?
Nothing. After onDestroy gets called the activity object will be garbage collected at some point. If the activity gets recreated it will be a new object. Your dagger component will also be garbage collected then along with your activity. I usually don't null my components in onDestroy because I deem it unnecessary.
This will although not hold true if you keep static references to your activity or have some other sort of memory and activity leaks. But if you have those it will not make much of a difference either if you null your component.
I want to customize the process of obtaining the authentication token from AccountManager.
AccountManager has getAuthToken() and getAuthTokenByFeatures() methods, but I want to implement a customized flow, which includes switching between activities, etc...
I wanted to implement it the following way:
public AccountManagerFuture<Bundle> getAuthTokenForActiveAccount() {
GetAuthTokenForActiveAccountFuture future =
new GetAuthTokenForActiveAccountFuture(MyActivity.this);
future.start();
return future;
}
Using the following nested class in my activity:
private static class GetAuthTokenForActiveAccountFuture extends Thread implements
AccountManagerFuture<Bundle> {
private final Activity mActivity;
public GetAuthTokenForActiveAccountFuture(Activity activity) {
mActivity = activity;
// TODO: write this method
}
#Override
public void run() {
// TODO: write this method
}
#Override
public boolean cancel(boolean b) {
// TODO: write this method
return false;
}
#Override
public boolean isCancelled() {
// TODO: write this method
return false;
}
#Override
public boolean isDone() {
// TODO: write this method
return false;
}
#Override
public Bundle getResult() throws
OperationCanceledException, IOException, AuthenticatorException {
return internalGetResult(null, null);
}
#Override
public Bundle getResult(long timeout, TimeUnit timeUnit) throws
OperationCanceledException, IOException, AuthenticatorException {
return internalGetResult(timeout, timeUnit);
}
private Bundle internalGetResult(Long timeout, TimeUnit timeUnit) throws
OperationCanceledException, IOException, AuthenticatorException {
// TODO: write this method
return null;
}
}
My idea was that I could create my own AccountManagerFuture object and "unblock" its getResult() method only after all the required steps were done (some of them include activity switching).
I got two issues here:
I need Activity context for switching to other activities when necessary, but the Activity I pass into constructor should be destroyed when I switch to other activity, but it won't because my Thread holds a reference to it... So I create a memory leak here. It seems that making the inner class non-static won't resolve this issue - the reference returned from getAuthTokenForActiveAccount() will still prevent from the outer Activity to be garbage collected. Is there any way I could achieve what I try to do without leaking the context?
Thread is eligible for garbage collection once its run() method returns, right? But in my case I want this thread to stick around because it also functions as AccountManagerFuture - it should be kept in memory until all references to it are gone. My question is this: is it enough to keep a (strong) reference to Thread for preventing it from being garbage collected? If not, how could I force this Thread to stick around until all references are gone?
At first. Making your Future non-static would make it having an implicit reference to its outer class - the Activity.
You should used some form of indirect communication between your future and your Activities..You should probably move it into Service anyway - did you think about any configuration change? Where do you hold the reference for your Future?
I would advice you to either move your flow into fragments - then you wouldn't have to switch Activities - and place your future into a retained Fragment (to make it survive orientation change) or move it into a background service and communicate with your activities (or any sort of UI) through broadcastreceivers or event bus.
Thread won't be garbage collected as long as you keep some reference to it. No matter if its finished or not. I think that you are confusing this with the fact that a running Thread won't be garbage collected even without keeping references to it. (I guess tha JVM does so, but I have to admit I'm not sure about this)
issue 1 solution:
use private WeakReference mContextHolder. when you need context - call mContextHolder.get() and check on null;
issue 2 solution:
Use Service which will host your threads.
Problem:
I'm saving some data in a singleton class... Sometimes it happens, that this singleton returns null data, from which I derive, that it was destroyed...
My idea/thoughts:
Actually, I thought, the singleton will live as long as the application lives and as long as the application remembers anything else like fragments state for example, my singleton will exist with it's last data too. Isn't this correct?
concrete problem:
My case is following: I go from my main fragment to a sub fragment and save an selected object in my singleton... I stop using my app and come back after some time. My app remembers it's state and recreates the fragments, my fragment want to get the selected object from my singleton and get's null.
I thought, a singleton should exist as long as the application exists and therefore needs no saving... Whenever the application is ended, nothing will be restored anyway and my app won't remember anything, so that's ok anyway. Is that a wrong assumption?
I need an answer to this question, because if I'm sure, that above thoughts are correct, I at least know, that I have to search for the problem somewhere else...
Here is a short summury of what I've found out (or have had forgotten)
Activitys can be recreated, although the application was destroyed
Singletons can be garbage collected if not referenzed from somewhere
So you HAVE TO SAVE your singletons! Otherwise, whenever your phone is on low memory, it may kill the application and create a NEW application, but RECREATE the activities...
For me, as I'm actually always use a single activity with fragments, it is easy to solve the problem:
when I create an activity, I call a static restore function (BEFORE calling get!!!)
in the onSaveInstanceState of the activity a always save the singleton to the bundle
=> so my singleton looks like following (base structure)
public class DataCache implements Parcelable
{
private static final String TAG = DataCache.class.getName();
private static DataCache mCache = null;
public static synchronized final DataCache get()
{
if (mCache == null)
mCache = new DataCache();
return mCache;
}
private DataCache()
{
// init...
}
public void save(Bundle outState)
{
outState.putParcelable(TAG, this);
}
public static void restore(Bundle savedInstanceState)
{
if (savedInstanceState != null && savedInstanceState.containsKey(TAG))
{
// only restore, if necessary, i.e. if application was destroyed but activity saved our last cache
if (mCache == null)
mCache = savedInstanceState.getParcelable(TAG);
}
}
}
I have a singleton, typical design with a static 'mInstance' to hold the global state. I notice that sometimes, while switching between activities, the mInstance variable becomes null and requires to be re-instantiated, causing all data to go empty.
Is this expected or am I doing something wrong? Is there really a chance that the static variables of a singleton would be nullified in such a scenario? I seriously doubt it and would like to hear some opinions.
Code is pasted:
public class RuleManager extends ArrayAdapter<Rule>
{
private static RuleManager mInstance;
private final Context context;
public RuleManager(Context context, List<Rule> r)
{
super(context,R.layout.main_menu_options_list_item);
if(r==null)r=new ArrayList<Rule>();
this.context=context;
}
public static RuleManager getInstance(Context context,List<Rule> r)
{
if (mInstance == null)
mInstance = new RuleManager(context, r);
return mInstance;
}
}
I just learned that storing Context like this would never let it being Garbage Collected and hence may cause a big leak.
You need to make your constructor private. I guess you may be calling a new on the constructor. Also make your getInstance synchronized.
A Service may be better than a Singleton if you want to hook into the LifeCycle. Here's more information from a related stackoverflow question.