Android Summit 2017 Recap

Introduction

I had the pleasure of attending to Android Summit 2017 (September 24–25) hosted by Capital One in Washington DC.

Here’s a summary of the talks I went to! Great talks all of them!

Android Summit 2017

Design + Develop + Test (Keynote)

by Kelly Shuster

Kelly showed how the perfect communication between designers, developers and testers should be.

One of the right tools to avoid long lasting conversations with designers is Zeplin. We use Zeplin at work and the fact that it gives you all the information you need without having to ask designers is unbelievable. Another thing you can use is creating concise and detailed Style guides and Guidelines such as:

  • Color palette
  • Default Zero and Loading states
  • Button states
  • Etc.

When talking about testing, she touched on two different types: User testing and Unit/Integration tests. For User testing, we can use tools like UsabilityHub to update mocks that can be tested by external people or Marvel that allows you create quick prototypes.

For testing, another good tip is to use your app as much as possible and play around with the features you’ve already built while you’re on the bus, waiting for a meeting, etc.

She probably gave the best tip of the day: Have an emulator with different configuration each day of the week. Vary the different API levels, screen sizes and configuration. If you don’t remember which one you used last, called them Monday, Tuesday, Wednesday, … GREAT TIP!

Pragmatic Kotlin on Android

by Josh Skeen

He recommended us looking at the Kotlin bytecode to inspect what our code is doing. He walked us through the properties in Kotlin: how to access the default getters and setters and how you can override them.

He went through some typical mistakes that the auto-converter does when you copy Java code into a Kotlin file and how to solve them in a Kotlin way.

About idiomatic Kotlin, he mentioned how to use the appy and let operators in a proper way.

What happens when Everyone is QA

by Cody Henthorne & Lana Khilko

Cody and Lana from Groupon gave their experience when testing in its company. They suggested engaging the entire company (and external people as well) to help improving the app. They have an average of 4.5 star reviews in the Play Store with over a million reviews.

What did they mean with EVERYONE?

  • Computers: This is how you scale, there’s so much the computer can do for you without human interaction. Automate repetitive tasks and use continuous integration.
  • Developers: Back your code up with Unit tests and UI automation tests. One cool term they used was: Developer first test pass: before handling your job to QA, test it first!
  • QA Staff: A culture of respect is needed. They have dedicated responsibilities and people being experts in certain areas of the app. They also have the final word on feature merges and often, they write test suites with developers.
  • Rest of the company: They organize Test parties before a release where they spend around 30 min to 1 hour to test the latest code that is going to go to production. Apart from that, they have a Catfood/Dogfood program: a kind of alpha version of the app with which you can share feedback easily. From that build, they get tons of data: number of users, sessions, crash logs, screen recordings, memory usage and performance metrics, etc. They get around 200 feedback submits for every release, more or less. For that, the use TestFairy. They can capture the logs because Catfood builds are completely different from release builds. They told us that they have a nice Catfood dashboard to see all that information.
  • Customers: Groupon has a dedicated team for release monitoring that are constantly analyzing and filtering bad reviews between other things. They use Google’s incremental rollouts and A/B test to get the most out of their customers.

How Espresso works

by Michael Bailey

One of the best talks of the day. He showed us how Espresso is built internally starting with a simple Espresso code

onView(withId(R.id.x)).check(matches(isDisplayed()))

A Matcher<View> shouldn’t match more than 1 view in your view hierarchy when implementing a custom matcher. It should match either 0 or 1 view. That matcher is what is passed through the onView method.

Espresso.onView registers for IdlingResources and constructs a ViewInteraction. The action you have to take after getting your view is done on that ViewInteraction object. It was interesting to see the code and how the ViewInteraction is created with Dagger and its constructor full of attributes.

ViewInteraction.check is executed synchronously on the Main Thread. It’s going to stop the Test thread and move to the Main Thread. If you try to operate with views in the test thread, you’re going to face problems and get flaky tests. When operating or doing something with the views, you should do that on the Main thread.

  • UiControllerImpl.loopMainThreadUntilIdle() Checks if the Main Thread is idle for a number of things: AsyncTasks threads, IdlingResources, etc.
  • IdlingResource is a public Espresso API that acts as a wrapper around something in your app that can be either be busy or idle and that tells Espresso if it has to wait or proceed.
  • Inside the Main Thread, Espresso is always checking for every single message that goes into the Main Thread queue, when there’s a message it is processed instantly and then checking again until it gets idle. This is what makes Espresso reliable and fast.
  • After waiting for the MainThread to be idle, it goes through the view hierarchy and gets the View that we’re asking for. You have a different Window object per activity or dialog, and each window has its view hierarchy. Espresso has the logic to go through all the Windows in memory and see with which one the user is interacting with.

ViewAssertions.matches tells you if that assertion matches or not. ViewMatchers.isDisplayed is a Matcher<View> that implements isDisplayedMatcher() and checks if the view is completely visible on the screen (with the globalVisibleRect attribute) and checking if the view is visible to the user (also checking for the visibility of the view and its parents).

How does an activity get launched synchronously? ActivityTestRule is going to launch the activity with the default configuration before running the test. It uses the JUnit 4 Rule mechanism. MonitoringInstrumentation.startActivitySync has a separate thread pool to call the startActivity method. That method uses the getTargetContext() to start the intent. startActivity is asynchronous, that’s why we have to add the Activity to the list of waiting Activities and listen for changes in that list until that Activity gets removed from it.

Android Architecture Components

by Chris Anderson and Christian Göllner

They walked us through the different components involved in the Google library:

  • Lifecycle. LifecycleObserver allows you to observe lifecycle events like ON_START and ON_STOP. If we have a Lifecycle object (LifecycleActivity or LifecyleFragment) we can add lifecycle observers to them on the onCreate method.
  • LiveData. We can use MutableLiveData to update consumers. Observers are lifecycle aware and they’re added and removed automatically from observing when the Emitter is not there. You can also create your custom LiveData class extending from LiveData and overriding the onActive and onInactive methods.
  • ViewModel. You can use it to retain data through configuration changes. The ViewModelProviders are in charge of creating instances of them and you can use a ViewModelFactory when the ViewModel doesn’t have an empty constructor. It’s expected to be used in a LifecycleActivity or LifecycleFragment and you can also reuse the same ViewModel in different Activities or Fragments.
  • Room. Massive code boilerplate reduction. No more manual conversion between Java and Cursor/ContentValue objects. It gives you compile time error checks on SQL statements. It’s also compatible with RxJava and LiveData.

From View to Pixel

by Britt Barak

We learned that the term Rasterization is used when drawing an Object (imagine a Java object) into pixels on the screen (on in a texture).

The GPU draws polygons and textures and displays them on the screen whereas the CPU only sees Views and Objects. The connection between them is OpenGL|ES using a DisplayList.

Everything should happen in 16 milliseconds due to the frequency an Android device refreshes the screen. If it doesn’t have time enough, the system caches what they could calculate. For that, it uses a BackBuffer and a FrameBuffer and the steps are: Swap buffers -> Execute -> Sync & Upload -> Draw -> Measure/Layout -> Vsync/Misc

To notify a change in the UI, you can call the method invalidate() which is going to re-draw the view or requestLayout() which is going to re-measure (this is in case something changes heavily, or changes in position or size).

Going to 100% Kotlin: A practical guide

by Dan Kim

Dan walked us through their first steps when they started programming in Kotlin.

The Unknown: When they started, there were a lot of unknowns, but they had to handle them. How to learn the new language? They had to be effective with it while still shipping. They had to convert their current Java backlog to a Kotlin one as well.

The practical, low-stress strategies to work as a team

  • Start with small conversions. He suggested not starting with tests because they’re small and isolated and they’re not very exciting. You need to get that momentum and get passionate about it. Because getting excited is important, you should start with Models, Utility methods and Adapters.
  • Forget about being perfect. A lot of people talk about Idiomatic Kotlin which refers to using Kotlin best programming practices.

Kotlin & Swift: Convergent Evolution?

by Stuart Kent

He would’ve preferred to call the talk Simultaneous Invention instead of Convergent Evolution.

Everything in Android dev is better than iOS dev but the language.

That changes know with Kotlin that can replace Java.

Over the years, Android & iOS development had some similarities: lifecycle, networking, accessibility, background processing and security. The concepts are exactly the same.

Nowadays, both languages have converged in some principles: platform-agnostic architectures (MVP, MVVM); Layout components (LinearLayout <-> UIStackView; ConstraintLayout <-> AutoLayout); development languages (Kotlin <-> Swift)

It’s never been easier for an Android developer to learn iOS development

Focusing on the new programming languages (Kotlin & Swift): They have similar principles and implementations: Accessibility, Expressivity and Safety. They were developed simultaneously but independently. Kotlin provides a semi-automatic migration whereas Swift requires a manual migration. The basic programming syntax is quite similar in both languages.

After that, he showed few examples of the new features that both Kotlin and Swift supports (Extension Functions and Default Parameter Values). First, showing how to program it in Java and then the Kotlin and Swift equivalent.

Kotlin and Swift are fundamentally and functionally similar. Learning and developing with both is viable.

Effective Android Data Binding

by Eric Maxwell — Twitter @emmax

Data Binding is a support library from Google to bind data directly to your views without having to find them by ID. You can automatically update views between other things.

@Bindable makes a property eligible for binding if the class extends from the BaseObservableclass. And you can trigger the observing field with the notifyPropertyChangedmethod. For example:

public class User extends BaseObservable {
private int count;
@Bindable
public int getCount() {
return count;
}
public void setCount(int count) {
this.count = count;
notifyPropertyChanged(BR.count);
}
}

Expressions in Data Binding are null safe and you can also specify a default value. Example: If displayName is null, then it’ll use the lastNameattribute.

android:text="@{user.displayName ?? user.lastName}"

The updates can also happen in background threads. It’ll get back to the Main Thread without you having to do anything about it.

BindingAdapters allow you to add custom attributes to views.

// Java code
@BindingAdapter({app:imageUrl})
public static void loadImage(ImageView view, String url) {}
// XML code
<ImageView
app:imageUrl='@{"http://whatever"}' />

Android Studio is smart enough to check type safety, so you cannot call app:imageUrl in a TextView or passing a value that is not a String.

Best practices in building Mobile libraries

by Emma Tresanszki

What’s the difference between a SDK and a Library? There’s a thin line between them. A library is a chunk of reusable code. A SDK is a library that provides more functionality, like making an existing service or API easily usable.

From a user point of view (other developers), you have to download the dependency from a repository and you have to manage the different versions. You shouldn’t let the libraries to silently add permissions to your app, you can use the marker selector to delete them.

From the developer point of view (builder of the library), in the design phase, you have to consider responsibility: fail fast when rejecting invalid params and do not discard future capabilities; library size: use few 3rd party dependencies or not at all; permissions: the library should check runtime permissions and block the feature if the permission is not granted.

How to publish to Maven Central? You have to update the gradle.properties file with GAV coordinates, Signing and SCM info. In the gradle.build file, you need to apply the maven and signing plugins with which you implement some methods to upload your archives.

How to make a good changelog? The principles are: they’re for humans, not machines; there should be an entry for every single version, the latest version comes first; group changes by type (added, changed, fixed, deprecated, …)

A practical guide to understand Rx Streams

by Mayank Mehta

There are different sources (elements that emit data) in RxJava: Observable, Flowable, Maybe, Single and Completable. You can listen to the data a Source emits with Observers.

Operators are functions that are applied on sources. Some examples are:

  • Merge operator: combines multiple observables into one.
  • Contact operator: concatenates output of multiple observables. The difference with merge is that it waits for the first observable that observes to finish before emitting items of the next source.
  • FlatMap operator: transforms the items emitted by a source into Observables (sources). Those new sources are flatten into one observable that emit the result of those new sources. Those emissions may interleave, so in the result observable, you can get items from the result of the flatMap applied to the second item received by the flatMap before the result of the flatMap applied to the first item received.
  • ConcatMap operator: this is like FlatMap but the emissions do not interleave.
  • Zip operator: combine emissions of multiple Observables and waits for one item from each source to emit a processed result.

Subjects were explained as a Walkie-Talkie. It can emit items and listen for items at the same time. It is a Source and an Observable at the same time.

How to Rxify non-RxJava code? We all have legacy code that we want to migrate to RxJava. If your code returns a value, you can use Single.create and call onSuccess on the emitter to emit (return) the value. If you’re not returning any value, you can use the method fromCallable() that is going to defer the execution of the method until someones subscribes to it.

One of the advantages of RxJava is making concurrency easy with Schedulers. You can modify the thread something is executed with the subscribeOnand observeOn operators. Remember that you can use multiple observeOn operators but only one subscribeOn will take effect.

Mayank continued explaining how we integrate RxJava within our app Architecture in the Capital One Wallet Android app. We have three different layers: Presentation, Domain and Data layers. Between layers, the communicate with Rx.

  • Data Layer: When accessing the data, we check first if the data is available in the Cache, if not, then we get it from our servers (network request). You can use the concat operator to achieve that behavior. The first argument to concat is an Observable that returns the information from the cache, and the second one from the network. If you combine that with the singleOrError operator, if the information is not in the cache, it’s going to try to get the information from the second observable that accesses the network.
  • Presentation Layer: The View and the ViewModel in the Presentation layer communicates with Rx. A PublishRelay is used by the Presenter to listen for user input that interacts with the View. The View subscribes to the presenter with a BehaviorRelay for the latest UI state. You can use the startWith operator with a Loading UI state to notify the View to show the Loading state before the data comes from the Data Layer (you can add this to the PublishRelay that receives user input).

The art of hiding Sensitive Info in Plain sight

by George Kortsaridis

What is there to hide? Source code, Manifests, Strings, Values, 3rd Party libraries, etc.

First he talked about attacking an app. How can we hack/modify applications?

  • We can Mock GPS locations and fake the device location.
  • What about the network layer? We can spoof network requests that go in or out of the device with WireShark.
  • We can decompile the app and see the source code easily, there are multiple open source tools available to do that (for example, dex2jar).

He showed us how we can decompile and see everything that is inside our application/project in plain sight.

How can we defend from these attacks?

  • We can use reflection to make it more difficult to read in case someone decompiles our app. If you add String obfuscation to it, it’ll be even harder for someone to read it. Also you can add name obfuscation to it, instead of naming you variable masterKey you can call it a . You can use ProGuard to achieve it.
  • APK Signature check. With this we make sure that no one publishes an app under our name. You can check the signature within your application.
  • Super critical algorithm? Hide it on the backend.

Long-running background tasks: A survival guide

by Mark Murphy

Limit background processing is an attempt by Google to reduce battery consumption and other waste.

Types of background work:

  • Foreground-triggered Work: transactional (e.g. file download), ongoing (e.g. media player) the user decides when to stop or start it.
  • Background-triggered work: periodic (e.g. scheduled server sync), push messages (e.g. GCM), system broadcasts as triggers (e.g. after app installs).

The historical thread recommendations are: if you can execute the job under 1ms use the Main thread. If not, use any other form of background thread. What if it’s over 1 second? Maybe you want to wrap that in a service. Over 15 seconds or background-triggered? Wakelock, WiFi-lock and foreground service. If you follow that pattern, even with the Android Oreo changes, your code still works.

Oreo started services are gone after 1 minute. After that, the service will be stopped and the system will call stopService(). It does not directly terminate your process, but increases the odds that it will terminate shortly. This affects any app whose targetSdkVersion = 26. Even if you target a lower SDK, the user can go to OS Settings and limit the background activity of your app. That option is only available if you app shows up in the battery information Settings screen.

The recommend approach is to start the Service in the foreground with the method startForegroundService(). You can call the startForeground() within that service if it’s going to take more than 1 minute.

What about the foreground notification? You can run the service, but you can’t hide it. Choosing a minimum-importance channel does not create a proper notification, just a line in the notification bar but the system will show another notification. If you use an important notification, then a notification with you service running will appear in the notification bar.

JobIntentService on Android7.1 and lower versions behaves like IntentService, but on Android 8.0+ uses the JobScheduler. It gives you a larger window for work.

There are also limitations with implicit broadcasts, targeting API 26, apps cannot receive implicit broadcasts via manifest-registered receivers. Self-broadcast with the signature permission are whitelisted.

Thanks for reading,

Manuel Vicente Vivo

Android DevRel @ Google

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store