onDestroy() - to set or not to set instance variables to null? - android

Is it a good idea to specifically set the instance variables to null in onDestroy() callback of the activity? Something like this:
#Override
protected void onDestroy() {
super.onDestroy();
mClassVariable1 = null;
mClassVariable2 = null;
mClassVariable3 = null;
}
If I remember correctly from Java SE, any references that are isolated & not connected to a running program & can be garbage collected anyways. So does this make the above superfluous?
On the other hand, the lifecycle in mobile devices being different, would the above be a best-practice?
I know it cannot hurt to do it, but sometimes there are a number of class variable (references to indivudual UI elements etc), so I'd really like to know for my own understanding, what's really going on.
Thanks in advance!

You had it right when you said that the garbage collector will pick up references that are isolated. Specifically, any graph of references not connected to the execution thread will be collected. Because of this, there is no good reason to set your variables to null that I can see. Any advantages would be far outweighed by the code maintenance cost.

Related

Better implementation of collecting child instances of given class

I have this code which provides the logic of this solution, but I'm aware that collecting an instance from within the constructor is dangerous.
Does anyone know a better solution?
The goal is to collect all instances that are extending this class. My preferred solution is the one the uses as little resources as possible (libraries, cpu, ram) although I know that there will always be a tradeoff.
I've tried something with reflection, annotation, classpath search but non of them seemed to be the silver bullet.
class Parent{
private companion object{
var childs = arrayListOf<Parent>()
}
constructor(){
childs.add(this)
}
}
If the intention is to collect all instances you should anyway somehow get those instances upon their creation (will it be the constructor or factory method, if any). Also you should somehow store them (maybe LinkedList is a better choice). So your approach seems reasonable.
But remember that within this approach these instances will be linked from a static place, which means that they wouldn't be garbage collected. If you don't want that, you could store them using a WeakReference (more precisely a collection of WeakReference<Parent>'s).

Static variable for state management

I'm having trouble understanding the problem in this scenario.
I have a class used for Analytics Tracking, lets call it FlurryTracker,
it has 2 methods StartTrackingScreen(ScreenName) and StopTrackingScreen().
Now if I have a static var called screenName and each time start tracking screen is called screenName is reassigned.
startTrackingScreen(activity: Activity, screen: DhTracker.Screen<T>) {
screenName = screen.getName()
val lastScreen = Singleton.getLastScreen()
//If last screen is not same as current screen
FlurryAgent.logEvent(screenName, true)
}
}
override fun stopTrackingScreen() {
//New screen will start tracking before lastScreen tracking is stopped.
if (enabled) {
FlurryAgent.endTimedEvent(Singleton.getLastScreen()?.getName())
}
}
companion object{
lateinit var screenName : String
}
These methods are called in onStart() and onStop() in the app itself.
So with that being said, we are only tracking 1 screen at a time because when the user transitions to a new screen, onStop() and onStart() will be called.
So even though screenName is static, every time the lifecycle methods are called, that static var is being reassigned. Since a phone can't have 2 activites running at the same time, there will only be 1 instance of my tracker active at a time.
I don't really see the problem with using a static here, although I know best practices say that screenName should be created with every new instance. Am I looking at this the wrong way?
You can do that.
The two main patterns for something like this are static variables & methods or a singleton (That is often static so you can use it from different paths without passing it around). Both of these approaches are functionally identical.
The negatives for the static class are:
Difficult to test due to the fact that you have to replace the static method
Difficult to create a second instance
Difficult to pass around if you decide you want to (Some people like to know what classes are used by a given path for testing purposes)
These aren't that bad, you can live with them--however none of these issues exist if you use a singleton. You can easily pass it around, change it's behavior, convert it to use injection instead of the singleton pattern, …
So I can't really come up with a reason to ever use the static approach, there aren't any advantages.

Issue about weakreferences

I have one or two weakreferences in my program.
Just for example:
ClassX myClassX= new ClassX(); //Line 1
WeakReference<ClassX> myWeakClassX = new WeakReference<ClassX>(myClassX); //Line 2
if(myWeakClassX.get() != null) // Line 3
{
//do something with reference //Line 4
}
My question:
How is it ensured that when at line 3 myWeakClassX.get() has a valid reference to an Object, it is also valid at line 4? I can imagine that if you are really unlucky, the GC does his job exactly "between" line 3 and 4. Please bear with me, because i'm relatively new to Android/Java..
Thanks for any explanation.
In Java, first thing to understand is Garbage Collector reclaims memory from objects which are eligible for garbage collection
Question is how is the eligibility defined ?
eligibility is decided based upon which kind of references are pointing to that object.
Why we need Weak Reference ?
If you create a Strong reference to an object, the object cannot be garbage collected. Whereas, A weak reference, simply put, is a reference that isn't strong enough to force an object to remain in memory. Weak references allow you to leverage the garbage collector's ability to determine reachability for you, so you don't have to do it yourself.
Issue here
Weak reference isn't strong enough to prevent garbage collection, so you may find (if there are no strong references to the class) that myWeakClassX.get() suddenly starts returning null.
What is the other option ?
Soft Reference
You use a SoftReference when you want the referenced object to stay alive until the host process is running low on memory. The object will not be eligible for collection until the collector needs to free memory. Loosely stated, binding a SoftReference means, "Pin the object until you can't anymore."
This way myWeakClassX.get() will not be null.
Examples of where we can use ?
In any secondary threads where you create a reference to the activity.
WeakReference weakActivity;
//In AsyncTask onPostExecute Method
Activity activity = weakActivity.get();
if (activity != null) {
// do your stuff with activity here
}
If you can referring to an Activity context elsewhere, you can use Weak reference.
While handling bitmap resources in imageview in another thread
http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
If you are creating any Hashmap or any widget to hold any data, you can use Weak reference. http://developer.android.com/reference/java/util/WeakHashMap.html
Usage is unlimited. It is up to the developer to utilize it at right places.
You are correct that during line 3 and 4 the get() operation can return null, as it is supposed to do. You can always copy the reference you get from get() operation into a variable (thus making it strong again) and use it within the if block safely. Because you still have a strong reference, the object will not be garbage collected.
A simple check for null can be:
if(myWeakClassX.get() != null)
{
ClassX myref = myWeakClassX.get();
if(myref != null) {
//use it
}
}
However in-case of activities, having a strong reference does not guarantee that the activity will not be destroyed and although you have a strong reference that is valid, the activity may throw exceptions when you try to use it as it is destroyed.
Example: If you are keep reference for an activity inside some AsyncTask, the activity might get destroyed (i.e orientation change) before AsyncTask runs. And although you will have a reference to it, you will get exceptions when you try to update UI.
That is where you can create a WeakRefernce to activity inside the AsyncTask and if the get() operation start returning null, you will know that the activity was destroyed by whatever reason and not try to use it.

Should I mark LruCache as volatile?

I recall reading somewhere that android guarantees that LruCache provides latest info for all threads, and that one thread's operation will complete before the same thread sees an edit on the cache from another thread. I am using LruCache to store bitmaps obtained from my app's server, and using a pool of threads to obtain bitmaps from the network.
Now I cannot find the reference to this in the Android docs or any other mention. Do I need to mark LruCache instances as volatile or set synchronize(LruCache) around cache operations?
mibollma is not wrong in his response regarding Android LruCache Thread Safety. People often mistake thread safety and atomicity.
If a class is thread safe, it means that, when for instance two threads call an operation on it, the internals do not break. Vector is such a class with every operation being synchronized. If two different threads call Vector.add, they will both synchronize on the instance and the state is not broken. For instance something like this:
synchronized void add(final T obj) {
objects[index++] = obj;
}
This thread-safe in the sense that no two threads will add an element at the same position. If it would not be synchronized they could both read index = 0 and try to write at that position.
Now why do you still need to synchronize? Imagine you have a case like this:
if(!collection.contains(element)) {
collection.add(element);
}
In that case your operation is not atomic. You synchronize once, when you ask if the element is already present and a second time when you add that element. But there is a window in between those two calls when another thread could make progress and your assumption of the collection not containing the element is broken.
In pseudo code:
if(!coll.contains(element)) { // << you have the exclusive lock here
//Thread 2 calls coll.add(element) << you do not have the lock anymore
coll.add(element); // << doomed!
}
So this is why the answer is correct in the sense that you should synchronize around non-atomic operations like
synchronized(coll) {
if(!coll.contains(element)) { // << you have the exclusive lock here
// Thread 2 wants to call << still holding the lock
// coll.add(element) but
// cannot because you hold the lock
coll.add(element); // << unicorns!
}
}
Because synchronization is pretty expensive the concurrent collections come with atomic operations like putIfAbsent.
Now back to your original question: should you make the LruCache volatile? In general you do not mark the LruCache itself volatile but the reference to it. If such a reference is shared across threads and you plan to update that field then yes.
If a field is not marked volatile a thread might not see the updated value. But again: this is just the reference to the LruCache itself and has nothing to do directly with its contents.
In your specific scenario I would rather have the reference final instead of volatile since no thread should set the reference to null anyways.
The question if you need to put synchronized around your cache operations depends on the case. If you want to create a single atomic operation, like putIfAbsent, then yes.
public void putIfAbsent(final K key, final V value) {
synchronized(lruCache) {
if(!lruCache.containsKey(key)) {
lruCache.put(key, value);
}
}
}
But later in your code, when you call just lruCache.get(key) there is no need to wrap that into a synchronized block itself. Only when you plan to create an atomic operation that should not interfere with another thread.

How to avoid unfortunate side-effects when using synchronized

This #Synchronized commentary warns that:
Locking on this or your own class object can have unfortunate
side-effects, as other code not under your control can lock on
these objects as well, which can cause race conditions and other nasty
threading-related bugs.
Avoiding race conditions is exactly the reason why I need to use the synchronized modifier, but when I see a warning like this, I realize that I may be causing more harm than good by not knowing everything about the system for which I am programming...
In my particular situation, I need to make sure that a specific method of a WebView-subclass is not interrupted by a PictureListener.onNewPicture().
That method was written by me, but it is only invoked by a Runnable.run() via a timer handler.
What should I check before deciding that it is safe to use the synchronized modifier to make sure that that timer-invoked method is not interrupted by PictureListener.onNewPicture()?
The solution is to use a private object to serve as the object's lock, like this:
In the class definition:
private Object syncRoot=new Object();
or
private static Object syncRoot=new Object();
In your code:
synchronized(syncRoot){
// put your code here
}
The reason why race conditions can occur is that other code has access to the objects locked on. Locking only private objects solves this.
Have a property in a class that you syncronhize on, rather than synchronizing on this or WebView-subclass object.
Most of those side effects would mostly affect server systems. I don't think that on Android you will have much of the problem as there is not much other code that could touch your method.

Categories

Resources