For the Karma Android (and iOS app) we need to update the hotspot status every second. We'll consider the exact implementation a detail suffice to say that every second some callback needs to be triggered that performs the necesary update. I'm writing this gist to try and explain what I'm trying to do and to get feedback on my approach from experienced developers.
- The main activity has an instance of a
HotspotStatusUpdater
class (initialize inonCreate
) - In
onResume
I callhotspotStatusUpdater.startUpdatingHotspotStatus(this);
(this
is a callback that implements theHotspotStatusCallback
interface) - In
onPause
I callhotspotStatusUpdater.stopUpdating()
;
Abstractly the hotspot status updater was implemented like this:
- When it's initialized create the client that is responsible for actually update the hotspot status. The updater is simply a host for calling this client every second.
- Create a
ScheduledExecutorService
usingExecutors.newScheduledThreadPool(1);
- When
startUpdatingHotspotStatus
is called usescheduledExecutor.scheduleAtFixedRate
to schedule a fetch every second - When the client calls back with the update hotspot status callback to the activity
Looking back after only a little over a week of Android development I realize this is a flawed approach. It is flawed because it does not take the Activity lifecycle into account. More concretely the client reports a new hotspot status on a different thread. When the client finishes it posts it update on it's own thread meaning you're calling back to your UI on a background thread.
This I initially fixed using:
Handler mainHandler = new Handler(updater.context.getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
callback.hotspotStatusDidUpdate(hotspotStatus);
}
});
At first I thought this was just Java being Java. I dislike this because it puts me as a developer very close to actual threading which is something you should keep me (and most other developers) very far away from.
Even after this 'fix' I kept running into random crashes with configuration changes (rotated the device). I kept adding conditionals until I realized that if I look at this code 1 week later I have no clue which edge case that conditional is fixing. I started looking for other approaches that are hopefully more idomatic Android. This is what I have come up with right now. Feel free to give me feedback.
- The
MainActivity
hosts a UI-lessHotspotUpdaterFragment
- The
HotspotUpdaterActivity
uses aAsyncTaskLoader
subclass calledHotspotStatusLoader
to 'load' the hotspot status - The
AsyncTaskLoader
uses something (not sure what yet) to triggeronContentChanged
on the Loader every second
My assumption is that because I'm using a loader, which are designed to work with activities and fragments, I will have to deal less with the activity lifecycle. If you have any feedback to this approach please let me know! :)