Google I/O 17 — What you might have missed
There are endless articles listing the main announcements from this year’s Google I/O, but unless you attended or took the time to watch the videos of all the talks, then you may have missed many smaller items that as an Android developer you should be aware of.
Firstly, there have been a raft of updates to the Play Store itself. A lot of these are aimed at providing you with more detailed information on how your app is performing in the wild, but there are also some nice additions for release managers. Here are some highlights:
Android Vitals is an initiative by Google to improve general app performance and stability. In this section of the Play Store you can see ANRs (App Not Responding) and crashes for your app. This is nothing new, but what is new is that all of these are now automatically reported from users that have agreed to share “usage and diagnostic data” on device setup, whereas before a user had to manually agree to send each crash report. This means that you’re likely to see a big increase in the amount of crashes you see in the Play Console! This may be alarming at first, but it paints a much more accurate picture of how stable your app is for users.
Besides critical failures like crashes and ANRs, Vitals will also give you an indication on how your app performs from a rendering and battery viewpoint. Nobody likes janky apps, and one of the quickest routes to getting your app uninstalled is if a user discovers that it’s excessively draining their battery. The Vitals section of the Play Store helps here by giving statistics on rendering speed and excessive wake ups or stuck wake locks. Furthermore, it will also alert you if your app is performing in the bottom 25% of any of these metrics.
Often as developers we tend to have high performance devices, which may not give an accurate reflection of how our apps perform for the majority of users, so these new metrics in the Play Store are a very useful addition, even if it’s just to affirm how awesome our apps actually perform in the wild.
Before now the Play Store showed you the top 10 devices that your app was installed on. This was mildly interesting but basically useless when you needed to know the install numbers for a particular device, which might happen, for example, if you’re experiencing a hard to resolve bug on a certain handset and are considering not supporting it.
This problem is now resolved with the addition of the Device Catalogue. Now you can view details for every single device that your app is installed on. This allows you take a much more informed decision before you consider excluding a device, and perhaps more importantly, makes the process of excluding it much easier as it can now be done with the click of a button in the Store.
Google Play App Signing
The Play Store now gives you the option to manage the signing of your app for you. The main advantage of this is that you no longer need to worry about your release key getting lost or compromised. You can upload it to Google’s servers where they’ll use it to sign your apps and you no longer need to worry about distributing it amongst other developers in your organisation who may need it to perform releases. You do still need an upload key, which is used to sign your apk so that it can be uploaded to the store. However, unlike your release key this can be changed in the event that it becomes compromised.
Another benefit of letting the Store manage your app signing is that it will rebuild your app, optimising it in the process, and generate different apks for the various device groups you support. This means that the resulting apk size that users need to download will be smaller, potentially increasing installs.
Ok so this feature isn’t actually new, but it had gone under my radar so was new to me…
No matter how much we test our apps there’s always an element of trepidation as we hit the Publish button. Well, the pre-launch report function should go some way to alleviating this.
If you opt in to this, each time you upload an apk the Store will crawl your app using a handful of real devices and inform you if it detects any issues. You can even supply it with sign-in credentials so that it can get past any login gateway your app may have. The resulting report includes a full logcat and a video recording of the process.
In theory this is a very useful function, even if just for peace of mind. However, in practice (so far) we’ve found that the crawler is actually pretty limited and doesn’t come anywhere close to crawling an acceptable percentage of the app. Hopefully this is something that will improve as the feature matures.
From an Android development perspective, Kotlin support undoubtedly created the biggest buzz at I/O, but probably the second most talked about thing amongst developers was the Architecture Components talks.
Until now Google has taken a hands-off approach to how an Android app should be architected, but they’ve finally broken their silence and given their opinion on how to best architect an app. Perhaps more importantly, they’ve also released a set of libraries to help you implement their recommended practices.
Google has finally admitted that the Android lifecycle can actually be really difficult to develop for, especially in a complex app where we may have multiple components running, all with behaviour tied to the lifecycle state. In response, they’ve added some new classes designed to ease the pain of the most common lifecycle related issues developers tend to encounter.
Ever find that your onStart and onStop methods tend to end up as a list of calls to start/stop various components? Well those days are are (potentially) coming to an end, as now each individual component can be made lifecycle aware; meaning that it can do its own initialisation and cleanup without being managed by the activity.
There are two steps involved in this. Firstly, pass a Lifecycle object to your component (this can be obtained from an Activity or Fragment) and finally have your component implement the LifecycleObserver interface. This interface lets you annotate any events so that they’re called when the corresponding Lifecycle event is triggered (ON_PAUSE, ON_RESUME etc.). Furthermore, the Lifecycle class also lets you query the lifecycle state at any time.
LiveData is an observable data holder. You might already be using a library such as Rx for such things, but the advantage with LiveData is — yes you guessed it — that it’s lifecycle aware. This has advantages such as knowing when an observer is or isn’t active so that, for example, you could stop requesting location updates when the LifeCycle becomes inactive. It also reduces common risks associated with observables such as memory leaks and crashes due to activities receiving callbacks while in an invalid state.
Note that while there may be some overlap in functionality between LiveData and reactive libraries such as Rx, that doesn’t mean they’re mutually exclusive. You may still want to use them to avail of the extra power and convenience of their functions and operators such as groupBy(), flatMap() etc.
The ViewModel class is designed to store and manage UI-related data so that the data survives configuration changes such as screen rotations.
A common scenario would be where your Activity or Fragment makes a network call in onCreate, but while this is being executed, the user rotates the device. This could result in duplicate network calls being made. Not only is this slow and inefficient, but could potentially also lead to memory leaks.
By using a ViewModel to manage the data, this problem is solved due to the fact that it survives configuration changes. In our example, the Activity would request the data from the ViewModel, which would make the network request. After the activity is recreated, the view model will supply it with the data that it has already received from the previous network request.
Other use cases for using a ViewModel include sharing data between fragments. An activity’s ViewModel can be made accessible to all of the activity’s fragments, potentially negating the need for defining complex interfaces in order to pass data around.
When it comes to using a database in your app you have the option of using SQLite directly or using an ORM (Object-Relational Mapping) library. The latter can eliminate a lot of boilerplate and even increase stability and ease of maintenance due to the fact that SQL is not verified at compile time. However, anyone who’s worked with ORMs extensively will no doubt have encountered a scenario where the abstraction becomes a barrier to trying to accomplish the task at hand and they wished that they could just write the damn SQL directly. Well, Google has you covered here with their new Room Persistence Library.
Now, I’m not saying that Room is the first or only library to achieve this, but it does appear to strike an excellent balance between abstraction and control. Furthermore, its core concepts are pretty easy to grasp, with 3 main class types to use: Database, Entity and Dao.
The Database class is used to create a database holder and defines a list of Entities and Data Access Objects (DAO).
Entity is used to annotate your model classes to indicate that a database table should be created for them.
Your Dao will be an interface that defines the CRUD methods for your model. Using an @Query annotation you specify the SQL to be used on your get methods. This concept will feel familiar to anyone that regularly uses the Retrofit library.
For more details check out the official documentation here.
If you frequently use fragments, there was a talk called Fragment Tricks that’s worth checking out. Firstly, they acknowledged that there are times that a custom view is more appropriate and gave some useful rules of thumb on when to choose which:
Don’t use a fragment when a view will do but don’t add outside dependencies to your views.
We can expand on this by saying:
Views display info and publish user interaction events — draw text, click, scroll etc.
Fragments integrate with lifecycle and may be aware of other app components — bind to a service, communicate with your app’s data model etc.
There were also some useful backstack and navigation tips, but one new API stood out. Anyone who has worked extensively with fragments has no doubt encountered an exception similar to the following:
java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
The most frustrating thing about this is that there was no concise way to check whether or not state had actually been saved… until now. Version 26 of the support library now has a Fragment.isStateSaved() method! Not exactly groundbreaking stuff, but useful to know.
Somewhat disappointingly, the security talk was mostly about what they’ve done to harden the OS rather than what we as developers should do to make our apps more secure. However, there were some new additions that would interest anyone that doesn’t want their app being installed on a compromised device.
Firstly, an API has been added to Android’s Verify Apps function (which you may never even have noticed as it’s buried deep in the settings). This lets your app query whether any potentially harmful apps are installed on a device, giving you the option to disable functions of your app if you suspect there’s a threat.
There is also a new SafetyNet attestation API, which can be used to the same end. The api will return two different boolean values; ctsProfileMatch and basicIntegrity. The latter, as the name suggests, is the less strict of the two and basically tells you if your app is installed on a physical device (not an emulator or script) running a non rooted Android OS with no signs of system integrity compromise. For ctsProfileMatch to pass, the device must adhere to the above criteria, but also must be a certified compatible device that isn’t running a custom ROM or have an unlocked bootloader. This API is used by Google’s own Android Pay app to disable functionality if it’s installed on what they deem to be an insecure device.
Anyone who has been tasked with porting an iOS app to Android, or perhaps worked on an app that was simultaneously being developed on both platforms at once, will probably have cursed at how easy iOS devs seem to have it when it comes to creating smooth fluid animations. Thankfully Android has done a lot of catching up on this front in recent years and Support lib 26 represents another step in the right direction with the addition of new physics-based animations.
The new APIs takes forces like velocity, inertia and friction into account giving much more realistic and natural looking animations. Take the following as an example:
Check out the official documentation for more examples, including some impressive effects gained from chaining SpringAnimations.
The above are just a small selection of the more ‘under the radar’ type highlights from I/O 17. I’d highly recommend perusing the list of talks at the I/O website for anything that might interest you.
Overall, attending was a fantastic experience. It really was impressive to witness the amount of preparation and organisation that had clearly gone into the event. Oh… and we got a free Google Home!
Roll on I/O 18!