References in Java. Considerations in Android.

References are handled differently across different programming languages. Given that I work with a number of different languages it is important that I have a clear understanding of how they work.

References in Java have caused me a few issues - issues that are mainly a result of their utilisation within the context of the Android framework.

This post seeks to clarify how references work in Java whilst also outlining some considerations when working with Android.

Jon Skeet outlines the most important points quite definitively:

  • "Everything in Java is passed by value
  • "The values of variables are always primitives or references, never objects."
int x = 0;

//We pass the value 0 to foo - 0 is an int (primitive)
foo(x);

String y = "This is a string";

//We pass a reference (by value) to the String object containing "This is a string"
bar(y);

Another useful explanatory quote that I found here is:

"Java modifies the meaning of 'pass by reference' from languages like C/C++. In C/C++, the term 'pass by reference' means passing the value of the variable's address (this is what a pointer is!)"

There is an analogy pertaining to balloons which states that passing an object variable to a function is akin to attaching another string to a balloon.

If in the bar function mentioned above one were to state y = new Thing() you would essentially be reattaching the string to a new balloon.

Significance in Android

The significance of this within Android is that often you might have a Thing instance in your activity, a property of which you would like to update.

You want to also have access to this Thing in a displayed Fragment, and you want it to be the case that updating the variable in your Activity will make the changes in your Fragment too.

Example

In my Activity I have an instance property var thing = new Thing();.

Within my onCreate method I create a Fragment using a static newInstance method (see here) and add it to my view. What exactly have I passed to my Fragments initializer?

When I pass the variable thing to my Fragments initialiser I am attaching another string to the same instance of Thing in the heap.

If I now change a property of the Thing within my Fragment e.g thing.key = "newKey";, then that change will be reflected if I access it within the Activity because both 'strings' point to the same object.

The problem

The problem that arises can be demonstrated in this simple demo that I have put together.

When the initial Activity is created we instantiate a new Thing instance. The constructor for Thing sets the value of a key property to the current timestamp.

We pass this Thing when instantiating our Fragment and display the values of the key properties.

At this point we have two 'strings' pointing to the same balloon. The value outputted is the same because the 'strings' point to the same Thing object in the heap.

If I now click the Button, we change the value of the key property of the Thing referenced by the Fragment. This updates the key property of the Thing referenced by the activity as well because they both reference the same object.

If however we now rotate our screen, the Activity is recreated by the Android framework. The Fragment however has setRetainInstance(true) specified and as such the Android framework maintains the Fragment instance.

At this point the values displayed for the key property of the Activity and Fragment differ. The Activity has been recreated. A new balloon has been created, and a new string attached to it. The Fragment however still has a 'string' pointing to the original Thing object on the heap.

If now we press the Button, the key property of the Thing referenced in the Fragment increments. The key property of the Thing referenced by the Activity does not - the respective 'strings' now point to different balloons.

The third line (output on screen) pertains to a second fragment that I have created for demonstrations purposes - a 'Data Fragment'. This is a viewless Fragment which simply holds and retains data. You will notice that when following the steps above the value for the key property of the MainFragment and the DataFragment stays in sync. This indicates that when retaining Fragments (on orientation change for example), the Android framework is not doing anything untoward with our variables - the 'strings' in both point to the same balloon.

savedInstanceState

As a matter of intrigue, I also wanted to investigate the situation whereby a Fragment is completely destroyed, its state saved in savedInstanceState and then restored.

The Fragment documentation clearly states that in some situations the Fragment instance may still be completely destroyed:

"There are many situations where a fragment may be mostly torn down (such as when placed on the back stack with no UI showing), but its state will not be saved until its owning activity actually needs to save its state."

I was concerned that perhaps in the process of parcelling a Parcelable object and then restoring it from a Bundle our 'strings' might be manipulated by the Android framework. This turns out not to be the case ! Wahoo !

In the demo (linked above), I have saved the Thing instance of our MainFragment and restored it in onViewStateRestored (e.g after an orientation change). The fact that pressing the Button after an orientation change updates the key value for both MainFragment and DataFragment indicates that everything is how we would like.

Extras

At this point I was becoming increasingly intrigued, and as such wanted to see how 'extras' work in respect of the subject matter. Sadly in this case the results were less positive :(

You may have been wondering as to why there is a 'Start new activity' button in my demo. Well, the reason is so that we can see how the Android framework handles passing variables to new Activities by proxy of 'extras'.

When we click this button, we pass an extra containing our Thing instance from MainFragment.
If you look at the logcat output of the new Activity you will see that the key value of the Thing passed to the new Activity is one and the same as that from the MainFragment (to be expected).

What i have then done is implemented an update to the Thing key in MainFragment. This is done on a 5 second delay I.E After opening the second Activity, 5 seconds later we update thing in MainFragment.

In the onCreate method of ExtraActivity we have set a 6 second timer after which we will check the key property of the Thing contained within the ExtraActivity.

We would hope (in an ideal world) that these values would be one and the same, and that the strings are pointing to the same balloons. Sadly they are not.

I have had a look through the Android source code to try and gain an insight into why this is the case. On the face of it, both saving instance state and passing extras transmit data by proxy of a Bundle. I will of course follow up if I gain any further insight on this. If you have any ideas, perhaps you could fill me in in the comments?

Implications

The implications of this are pretty obvious - namely that when working with data that needs to be utilised and manipulated in multiple locations, you need to be very careful about where your variables point.

If you are not, you may end up with data integrity issues across areas of your application.

Hopefully this has provided a little clarity on references within Java, and provides insight into the appropriate patterns to utilise when developing Android applications.

If you have any questions or comments, please feel free to post them. I am always happy to help.