Tuesday, January 29, 2013

Android: is onDestroy the new onStop?

Conventional Android development logic dictates that if there is some action you want to perform (or rather, stop performing) when your Activity is no longer visible to the user, do it in onStop(). Likewise, if there is some action you want to restart performing when the user restarts interacting with your Activity, do it in onStart(). The disadvantage of this approach, of course, is that it wouldn't play well with device orientation changes.

This post explores a couple of solutions to this problem, and concludes that there are cases where one has no choice but to postpone the actions that would be ideally taken in onStop(), to onDestroy().

A trivial (incorrect) example

public TrivialIncorrectActivity extends Activity{

    //onCreate() and other life-cycle overrides like onResume() go here ...

    @Override public void onStart(){
        super.onStart();
        startMakingThatPeriodicRestCall();
    }

    @Override public void onStop(){
        super.onStop();
        stopMakingThatPeriodicRestCall();
    }

    // ... Other life-cycle overrides like onDestroy() go here

}

This example is incorrect. Every time the user rotates the device, your app would stop making a REST call and then again start making the call. Not good at all.

setRetainInstance to the rescue . . .

API 11 introduced the Fragment API, and along with it, the setRetainInstance method, which is also usable with older versions of Android by means of the support library. You can go through the documentation to understand the effect of a setRetainInstance(true). Essentially, when a configuration change is happening, even though the hosting Activity is being re-created, the Fragment instance is not destroyed.

So, this allows us to improve upon our previous example.

public IncorrectRotationTolerantActivity extends FragmentActivity{

    private static final String TAG_RETAIN_FRAGMENT = "RetainFragment";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(savedInstanceState == null){
            getSupportFragmentManager().beginTransaction()
                .add(IncorrectRetainFragment.newInstance(), TAG_RETAIN_FRAGMENT).commit();
        }
    }
}

public class IncorrectRetainFragment extends Fragment{

    public IncorrectRetainFragment(){}

    public static IncorrectRetainFragment newInstance(){
        IncorrectRetainFragment frag = new IncorrectRetainFragment();
        frag.setRetainInstance(true);
        return frag;
    }

    @Override
    public void onStart() {
        super.onStart();
        startMakingThatPeriodicRestCall();
    }

    @Override
    public void onStop() {
        super.onStop();
        stopMakingThatPeriodicRestCall();
    }

}

This code snippet still doesn't do what we want it to do. It does not prevent re-making that REST call during orientation changes. Why?

Because, setRetainInstance doesn't prevent a Fragment's onStop() from being called - it just prevents onDestroy() from being called. So, even if you ask for a Fragment instance to be retained across configuration changes, the onStop() method of the Fragment is always still called when the device is rotated.

onDestroy() is the new onStop()

To fix the problem, postpone stopping the REST call to the onDestroy() of the Fragment. Similarly, start making the call in onCreate() instead of in onStart(), since onCreate() is not called when the device is rotated, but onStart() is.

public RotationTolerantActivity extends FragmentActivity{

    private static final String TAG_RETAIN_FRAGMENT = "RetainFragment";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if(savedInstanceState == null){
            getSupportFragmentManager().beginTransaction()
                .add(RetainFragment.newInstance(), TAG_RETAIN_FRAGMENT).commit();
        }
    }
}

public class RetainFragment extends Fragment{

    public RetainFragment(){}

    public static RetainFragment newInstance(){
        RetainFragment frag = new RetainFragment();
        frag.setRetainInstance(true);
        return frag;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onStart(savedInstanceState);
        startMakingThatPeriodicRestCall();
    }

    @Override
    public void onDestroy() {
        super.onStop();
        stopMakingThatPeriodicRestCall();
    }

}

This seems so semantically wrong though. onDestroy() represents the end of the entire lifetime of an Activity/Fragment and what we really wanted to do was monitor the visible lifetime. Also, there is no guarantee that onDestroy() will ever be called. If you really try out this example on a phone or emulator, chances are that you'll never see the Rest call being stopped - at least not right away.

A more correct, more restrictive solution:

There exists another solution to this problem - but it works only on API 11 and later, because it uses methods introduced in API 11 - isChangingConfigurations() and getChangingConfigurations().

public RotationTolerantActivity extends FragmentActivity{

    private boolean mRotated;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        Boolean nonConfigState =
            (Boolean)getLastCustomNonConfigurationInstance();
        if (nonConfigState == null) {
            mRotated = false;
        } else {
            mRotated = nonConfigState.booleanValue();
        }
    }

    @Override 
    public void onStart(){
        super.onStart();
        if(!mRotated){
            startMakingThatPeriodicRestCall();
        }
    }

    @Override
    public void onStop(){
        super.onStop();
        mRotated = false;
        if (isChangingConfigurations()) {
            int changingConfig = getChangingConfigurations();
            if ((changingConfig & ActivityInfo.CONFIG_ORIENTATION) == ActivityInfo.CONFIG_ORIENTATION) {
                mRotated = true;
            }
        }

        if(!mRotated){
               stopMakingThatPeriodicRestCall();
        }
    }

    @Override
    public Object onRetainCustomNonConfigurationInstance() {
            return mRotated ? Boolean.TRUE : Boolean.FALSE;
        }

}

This solution is semantically correct, and works as expected. However, it only works on API 11 and higher, even though we extend FragmentActivity from the support library .

Bonus: Why onStop() and not onPause()?

The keen reader would have observed that this post talks about stopping un-needed tasks in onStop()and not onPause() - even though onPause() is the only one of these methods that is guaranteed to be called. Remember that after onPause() is called, the process could be killed in order to reclaim memory and thus onStop() and onDestroy() might never be called.

Yet, this entire post insists on using onStop() to stop un-needed tasks. The reason for this lies in the technique used in my library android-app-pause. Unfortunately, this library in its current form does not handle device orientation changes correctly. This will be fixed in a future release though.

Saturday, January 5, 2013

Extensibility and Immutability in Java

Objective:

To devise a way to make thread-safe, a Java class designed to be extensible.

Introduction:

Effective Java, Second Edition: Item 15 says "Minimize Mutability". One should always try to make a class immutable. This has several advantages that I will not go over here (Since Effective Java explains it all). I will however point out one of those advantages since it is central to this discussion:

Making a class immutable is the easiest way to ensure that the class is thread-safe.

There is however a problem: to make a class truly immutable, you must prevent it from being sub-classed. Either the class must be declared final, or it should have a private constructor and provide static factory methods instead of constructors. The reasons for this are outlined in Effective Java. The basic premise is that a sub-class can violate the immutability guarantees.

This must-not-be-subclassed restriction may be fine if you are applying immutability to some value object like User, Point, Account etc. However, the same requirement turns out to be overly restrictive if you are applying the concept to logic classes. This is because logic classes are often meant to be customized by extension.

A strongly-immutable logic class:

As an example of a logic class, consider the following ReportGenerator:

public final class ReportGenerator{
    private final DatabaseLayer mDatabaseLayer;
    private final PresentationLayer mPresentationLayer;

    public ReportGenerator(DatabaseLayer db, PresentationLayer pres){
        this.mDatabaseLayer = db;
        this.mPresentationLayer = pres;
    }

    public void generateMonthlyReport(User user){
        Report report = mDatabaseLayer.getReport(user);
        mPresentationLayer.present(report);
    }
}

The other classes have been ommitted for brevity. Assume that DatabaseLayer and PresentationLayer classes are themselves immutable. This makes ReportGenerator strongly immutable and hence, thread-safe.

Now, suppose in the next phase of the project, you need to add a way to generate a historical report. The easiest way that comes to mind is to inherit from ReportGenerator. Unfortunately, we cannot do this since in order to make ReportGenerator immutable, we have declared it final. One possible approach to solving this issue is making ReportGenerator weakly immutable. This is discussed in the next section.

A weakly-immutable logic class:

One can relax the restriction that an immutable class must not be extensible, while still maintaining the guarantees, provided the sub-class adheres to the established contract. This is done by removing the final modifier from the class declaration, and making all fields protected final, or keep them private final and provide getters which we then use in the sub-classes. Both these approaches are shown in the code below.

public class ReportGenerator{
    protected final DatabaseLayer mDatabaseLayer; //protected field approach
    private final PresentationLayer mPresentationLayer; //private field with accessor approach

    public ReportGenerator(DatabaseLayer db, PresentationLayer pres){
        this.mDatabaseLayer = db;
        this.mPresentationLayer = pres;
    }

    public PresentationLayer getPresentationLayer(){
        return this.mPresentationLayer;
    }

    public void generateMonthlyReport(User user){
        Report report = mDatabaseLayer.getReport(user);
        mPresentationLayer.present(report);
    }
}

We can now sub-class this as follows:

public class HistoricalReportGenerator extends ReportGenerator{

    public HistoricalReportGenerator(DatabaseLayer db, PresentationLayer pres){
        super(db, pres);
    }

    public void generateHistoricalReport(User user, Duration duration){
        Report historicalReport = mDatabaseLayer.getReport(user, duration);
        getPresentationLayer().present(historicalReport);
    }
}

We could also have added more protected final fields to the sub-class if needed.

What we now have is a weakly immutable class. This class is immutable as long as sub-classes adhere to the contract. It is a good idea to establish in the class javadoc, the expectation that sub-classes MUST preserve the same weak immutability restrictions that this class adheres to. If a sub-class willfully violates the contract, then the logic class cannot be depended upon to work correctly.

Here's an example to how to establish this contract:

/**
 * The logic class that generates the report.
 * ... ...
 * <br/><br/>
 * This class is <em>weakly immutable</em>. It has been kept open for 
 * extensibility. Sub-classes <strong>MUST</strong> preserve the immutability 
 * guarantees of this class. In particular, they must have only immutable 
 * fields; and must not override any of the methods defined in this class to
 * return a mutable reference.
 *
 */

public class ReportGenerator{
    //Class body omitted.
}

Since immutability is enforced by documentation rather than by the compiler, this is an acceptable compromise. It allows us to easily create thread-safe classes that are also extensible. This makes writing API's and frameworks that much easier.

Thread-safety is more than Immutability:

Of course, making a class immutable is not the only way to make a class thread-safe. A mutable class can be written such that it is thread-safe too. It is often desirable for an object to change its state during the execution of a program. How that is done is beyond the scope of this article. I suggest looking at Java Concurrency In Practice for details on this topic.

Extending the logic class by Composition:

There exists an alternative way to extend the functionality of ReportGenerator that does not involve inheriting from it: "Favor Composition over Inheritance" (Effective Java, Second Edition, Item 16). For completeness, I present the code for this approach here. Do note that this example uses the strongly immutable form of ReportGenerator.

public final class ReportGenerator{
    private final DatabaseLayer mDatabaseLayer;
    private final PresentationLayer mPresentationLayer;

    public ReportGenerator(DatabaseLayer db, PresentationLayer pres){
        this.mDatabaseLayer = db;
        this.mPresentationLayer = pres;
    }

    public PresentationLayer getPresentationLayer(){
        return this.mPresentationLayer;
    }

    public DatabaseLayer getDatabaseLayer(){
        return this.mDatabaseLayer;
    }

    public void generateMonthlyReport(User user){
        Report report = mDatabaseLayer.getReport(user);
        mPresentationLayer.present(report);
    }
}

public final class HistoricalReportGenerator{
    private final ReportGenerator mReportGenerator;

    public HistoricalReportGenerator(ReportGenerator reportgen){
        this.mReportGenerator = reportgen;
    }

    public ReportGenerator getReportGenerator(){
        return this.mReportGenerator;
    }

    public void generateHistoricalReport(User user, Duration duration){
        Report historicalReport = mReportGenerator.getDatabaseLayer().getReport(user, duration);
        mReportGenerator.getPresentationLayer().present(report);
    }
}

This approach works fine when the class hierarchy is only a couple of levels deep. If it gets deeper than that, then getting a handle to the members of the base class becomes unwieldy. For example, suppose we have the following:

public class AnnualReportGenerator extends HistoricalReportGenerator
public class LeapYearReportGenerator extends AnnualReportGenerator

Now imagine a method in LeapYearReportGenerator needs access to the DatabaseLayer object. The code for this would look lik:

mAnnualReportGenerator().getHistoricalReportGenerator().getReportGenerator().getDatabaseLayer();

This is clearly something you want to avoid. With the composition approach, you also lose the runtime polymorphism advantage.

Conclusion

To summarize what this article discussed:

  • The easiest way to make a class thread-safe is to make it immutable.
  • Strong immutability closes the door on extensibility.
  • It is often convenient to make a class weakly immutable. This allows it to be sub-classed.
  • If you make an immutable class extensible, clearly establish in the javadoc, the contract that sub-classes must preserve the immutability guarantees.

Other than these observations, we also saw that:

  • Immutability is not the only way to achieve thread-safety, and in fact immutability is not always desirable.
  • Instead of inheriting from a weakly immutable class, one can also extend the functionality by composing a class with a strongly immutable object as its member. This has its own pros and cons - and both approaches must be evaluated before deciding on one.