Welcome back. I'll finish this section by seeing what happens when the user's phone
battery dies. It's easy to test that using the emulator. Make sure you're
timing a task, then use the icon on the sidebar to open the extended controls window.
But before I continue I'd better give you a warning.
Don't do this with an emulator that you want to keep. It'll probably go okay, but
you could end up with an emulator that you can't start up. Emulators are
disposable things and you can always create a new one, but if you've spent a lot
of time configuring your emulator, then you might want to create a new one for
this step. That's what I've done. Alright.
The emulator is running and a task was being timed. I'll clear the logcat
because we want to see what gets logged.
In the extended controls, select battery. Set the charger connection to none,
the emulator default to an AC charger, and we'll set it back to that when we're finished.
Our emulator's now running on battery, or to be more accurate, it's behaving as
if it is. To simulate the battery dying, drag the charge level slider all the way to zero.
Okay, our battery's died, and the emulator shuts down, just like a real
phone would do. Before we start it up again, let's examine the logcat.
At the end, we can see MainActivity and MainActivityFragment, going through the
destroy phases of their life cycle. for both of them, we get onPause followed by
onStop. Depending on any warning dialogues we may have appeared as the
battery died, you may see onPause followed by onResume, first. That's fine -
what's important are the final onPause and onStop. Because it's Android that killed
the fragment and the activity, you should also see onSaveInstanceState being called.
That's interesting - when the user starts the app again, you may think that
instance state should be restored. This should behave like a device rotation, in
other words. Unfortunately, it doesn't, and you'll get a null bundle in onCreate
when the app is relaunched. The app will behave as though it's been closed by the
user, but they'll probably expect that. if they let their phone run out of battery.
Alright, onPause and onStop were called, and we can reliably use them to
store user data, if we want. There's something missing from logcat, though.
Have you spotted it? When you rotate a phone, the ViewModel doesn't get
destroyed. The ViewModel survives things like rotation and continues to exist in
memory. Unfortunately, though, the memory has been cleared. The device currently
has no power because it's battery died.
That's important to us, because the entry that's missing from logcat, is the TaskTimerView Model's
onCleared function getting called. At the moment, all we're doing in
there is unregistering the content observer to avoid a memory leak.
Obviously, a memory leak isn't an issue when the phone power's down. Where it
might be an issue, is if we decided to use onCleared to persist some data, such as
the current timing. It's fine to store data in the activity, or fragment on
Pause or onStop functions. We've just seen them being called in the logcat.
Don't use a ViewModel's onCleared function to persist data. If you
rely on it being called, horrible things will happen when the battery dies,
or Android has to kill the app for other reasons. If you decided to use a Shared
Preference to store the current timing, then I'd suggest doing that in the time
Task function. That way the current timing will be stored, at the same time
as the row is added, or updated, in the database. The bottom line is, don't rely
on onCleared for saving state. Alright, we were timing a task and the battery
died. Let's pretend our user is no longer travelling and connects their phone to a
charger. They can now stop timing the task. So let's see if that will work This
is where you may get problems with the emulator. We've tried this on fairly fast
computers with plenty of RAM. If your emulator runs slowly and is not very
responsive, you may struggle with this bit. I'll run the app again, and Android
Studio will start the emulator again.
Keep calm but work fast. When you see the side menu appear, click the icon at the
bottom again. Select battery on the left and put the charger connection back to
AC - that's over on the right hand side. If you don't do that, the emulator will
start up, see that it's battery has no charge and shut down again. Also, drag the
slider to give the battery some charge. The emulator might shut down again, if
you don't manage to connect the charger before the battery's level is checked.
If that happens, run the app again to start up the emulator and repeat those steps.
If that fails, you'll have to delete the emulator and create a new one. In our
testing, we haven't had any problems restarting an emulator with a dead
battery, but as I said, we're running fairly fast computers with lots of
memory. As you can see, my emulator started up again. Our code's worked
and it's still timing the task. I can long- tap the task again, to stop the timing.
That's pretty cool. The emulator's let us test battery conditions, and we can write
our apps to handle things, like the battery running out of juice. And that's
the end of this section. In the next section, we'll create the reports
activity, to display the timing data that we've stored.
I'll look forward to seeing you then.