Chris Arriola

Mobile app developer. Android enthusiast.

Getting Attached To Your State

Configuration changes occur in runtime and are caused by various events such as: when keyboard visibility changes, when language changes, or when orientation changes. This in turn causes any visible Activity to be reconstructed once the change finishes. For state to be recovered, it needs to be explicitly tied to Android’s parcelling mechanism via Bundle.

Saving State, The Wrong Way

Upon encountering state loss caused by a configuration change, say on an orientation change, 2 poor solutions are:

1. Locking the orientation mode

1
2
3
<activity 
    android:name="com.app.app.MainActivity"
    android:screenOrientation="portrait" />

This is an anti-solution and simply prevents the configuration change from occurring. This will not guard against the other 13 configuration changes as of API level 23.

Orientation should only be locked as a result of a UI/UX decision, and not for retaining state.

2. Handling configuration changes manually

1
2
3
<activity 
    android:name="com.app.app.MainActivity"
    android:configChanges="orientation" />

Again, this is a band-aid and not a proper solution. What if new configuration changes are introduced? Also this might cause some unintended consequences. Say for example you want to declare a landscape/portrait-specific resource, that resource will not be loaded automatically anymore and you need to explicitly load and apply it in Activity#onConfigurationChanged() instead. Not knowing this consequence may be a pain to debug.

Quoting Roman Guy:

“…it is sometimes confusing for new Android developers who wonder why their activity is destroyed and recreated. Facing this “issue,” some developers choose to handle configuration changes themselves which is, in my opinion, a short-term solution that will complicate their life when other devices come out or when the application becomes more complex. The automatic resource handling is a very efficient and easy way to adapt your application’s user interface to various devices and devices configurations.”

Indeed, it is good practice to allow the system to do what it was designed to do as it allows your application to behave correctly on varying devices especially as your application gets more complex.

Manually handling configuration changes should only be done sparingly and as a result of some constraint (e.g. performance reasons).

Saving State, The Right Way

Luckily, framework Views will automatically be saved and recovered for you—assuming all your Views have unique IDs. In other instances you need to explicitly retain state.

Retaining State In An Activity

1
2
3
4
5
6
7
8
9
10
11
12
13
@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    // This is called by the system so that any instance that can be recovered
    // when the Activity is recreated.
    savedInstanceState.putInt(SOME_VALUE, someIntValue);
    super.onSaveInstanceState(savedInstanceState);
}

public void onRestoreInstanceState(Bundle savedInstanceState) {
    // This is called by the system when the Activity is reconstructed.
    super.onRestoreInstanceState(savedInstanceState);
    someIntValue = savedInstanceState.getInt(SOME_VALUE);
}

There are other lifecycle events where state can be restored such as in Activity#onCreate(). Retaining state in a Fragment can be done in a similar way via Fragment#onSaveInstanceState(). Here’s a good resource by CodePath for learning more about how this works.

Retaining State in A Custom View

Retaining state in a custom View is a bit more involved but nonetheless also fairly straightforward.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
package com.operator.android;

import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.view.View;

/**
 * A custom {@link View} that demonstrates how to save/restore instance state.
 */
public class CustomView extends View {

    private boolean someState;

    public CustomView(Context context) {
        super(context);
    }

    public boolean isSomeState() {
        return someState;
    }

    public void setSomeState(boolean someState) {
        this.someState = someState;
    }

    @Override protected Parcelable onSaveInstanceState() {
        final Parcelable superState = super.onSaveInstanceState();
        final CustomViewSavedState customViewSavedState = new CustomViewSavedState(superState);
        customViewSavedState.someState = this.someState;
        return customViewSavedState;
    }

    @Override protected void onRestoreInstanceState(Parcelable state) {
        final CustomViewSavedState customViewSavedState = (CustomViewSavedState) state;
        setSomeState(customViewSavedState.someState);
        super.onRestoreInstanceState(customViewSavedState.getSuperState());
    }

    private static class CustomViewSavedState extends BaseSavedState {

        boolean someState;

        public static final Parcelable.Creator<CustomViewSavedState> CREATOR = new Creator<CustomViewSavedState>() {
            @Override public CustomViewSavedState createFromParcel(Parcel source) {
                return new CustomViewSavedState(source);
            }

            @Override public CustomViewSavedState[] newArray(int size) {
                return new CustomViewSavedState[size];
            }
        };

        public CustomViewSavedState(Parcelable superState) {
            super(superState);
        }

        private CustomViewSavedState(Parcel source) {
            super(source);
            someState = source.readInt() == 1;
        }

        @Override public void writeToParcel(Parcel out, int flags) {
            super.writeToParcel(out, flags);
            out.writeInt(someState ? 1 : 0);
        }
    }

}

TL;DR

  • Don’t save your state the wrong way 😅 Save your state the right way 😁

Code Like a Goldfish

There is an underlying hidden requirement in creating software products. It doesn’t just have to “work”; it needs to be molded in such a way that it can be changed, maintained, and scaled easily.

Last month, I gave a talk addressing this topic to the 1st cohort at Telegraph Academy—an immersive program that teaches underrepresented groups in tech on how to code. They were nearing their last week of the program so I thought it would be relevant to share some industry lessons.

TL;DR

  1. Design early

    The biggest mistake beginners tend to make is not taking the time to think through the pros/cons of a software design. Designing early makes it easier to find flaws, it’s much harder fixing those flaws once it’s expressed in code.

  2. Don’t over optimize

    This doesn’t just apply to algorithms (e.g. trying to get O(n * log n) performance vs O(n2) on a small dataset), but it also applies to software design. Don’t over-engineer or over-genericize a problem if it doesn’t have to be.

  3. Don’t repeat yourself (DRY)

    Code repetition means if something needs to be changed/fixed, it needs to be changed in all parts of the code which is error-prone. Have one source of truth and abstract where appropriate.

  4. Think small

    Smaller classes, methods, and files are easier to maintain.

Check out the slides here.


Android Wear App: reMIND

Pay attention.

The statement above reminds us that being attentive costs something. To fully listen and be aware requires some level of deliberate focus.

Given stimuli that constantly try to grab our attention, it’s kind of hard to do that.

Recently, I’ve been meditating a lot and have been using apps like Calm.com and Headspace. I find meditation extremely useful as it helps bring awareness to what you’re feeling in the moment. As simple as it sounds, it’s actually really important because your mood determines the quality of your actions. Feeling really motivated and energized? Do the hardest and most important task on your list. Feeling scatterbrained and under the weather? Do simple and menial tasks instead.

Aside from meditation helping with self-awareness, I find that it also helps with appreciating the moment. Worries about the past or the future are irrelevant because the present is only what is. That understanding brings peace of a mind and encourages just being with it.

As a way to remind myself and others of this fact, I created an Android Wear app that sends reminders throughout the day to be present. Upon being reminded, you can then do your personal mindfulness practice or simply appreciate the moment. Check it out.