Code News

After Charlottesville, Dark Humor Helps Twitter Grieve

Sex, Drugs, and the Inside Lane: Recapping the 2017 World Championships of Track

James Damore’s Google Memo Gets Science All Wrong

9 Cool Notebooks to Help You Write Right

One Year Later, 'No Man's Sky' Is Still Worth Exploring

Tech Companies Have the Tools to Confront White Supremacy

'Game of Thrones' Recap, Season 7 Episode 5: The Sins of the Father Persist

Why Morningstar Moved to the Cloud: 97% Cost Reduction

  •  

    Enterprises won't move to the cloud. If they do, it's tantamount to admitting your IT group sucks. That has been the common wisdom. Morningstar, an investment research provider, is moving to the cloud and they're about as enterprisey as it gets. And they don't strike me as incompetent, they just don't want to worry about all the low level IT stuff anymore. 

    Mitch Shue, Morningstar's CTO, gave a short talk at AWS Summit Series 2017 on their move to AWS. It's not full of nitty gritty technical details. That's not the interesting part. The talk is more about their motivations, the process they used to make the move, and some of the results they've experienced. While that's more interesting, we've heard a lot of it before.

    What I found most interesting was the idea of Morningstar as a canary test. If Morningstar succeeds, the damn might bust and we'll see a lot more adoption of the cloud by stodgy mainstream enterprises. It's a copy cat world. That sort of precedent gives other CTOs the cover they need to make the same decision.

    The most important idea in the whole talk: the cost savings of moving to the cloud are nice, but what they were more interested in is "creating a frictionless development experience to spur innovation and creativity."

    Software is eating the world. Morningstar is no doubt looking at the future and sees the winners will be those who can develop the best software, the fastest. They need to get better at developing software. Owning your own infrastructure is a form of technical debt. Time to pay down the debt and get to the real work of innovating, not plumbing.

    Here's my gloss of the talk:

    6 days 11 hours ago

Android Architecture Components: Lifecycle and LiveModel

  • In the last part of this series, Introduction to Android Architecture Components, we talked about the new Android Architecture and why it was developed. Basically, the new architecture addresses some known Android issues by offering a bundle of components tailor-made for the system. These are the building blocks of the architecture. We've already had a quick look at these components, so now it is time to start to deep dive into them. 

    In this tutorial, we'll take a close look at the Lifecycle and the LiveModel components. While we're exploring these, we're also going to check out some code snippets from a sample application. Since we're talking about Android's new paradigms, the snippets are all made with the awesome Kotlin.

    If you don't know Kotlin yet, please don't be afraid to follow along; the implementation is extremely close to Java, and I'm confident that you'll be able to understand it. If you want to learn more about Kotlin, Jessica Thornsby wrote an excellent series here on Tuts+ about Coding Android Apps in Kotlin. You should take a look!

    1. The Sample Project

    We provided a small application demonstrating the concepts that we're talking about in this tutorial. The app's name is MyWeatherApp, and it allows the user to fetch the day's weather using a city's name or the user's current location. The app's logic is quite simple, but you could improve on it to create your own application.

    As you can see in the diagram below, the architecture conforms to the one proposed by Android, and we used the new Architecture Components package as much as possible, keeping things simple enough for a basic analysis. As a bonus, we're using Dagger 2 as a Dependency Injection library. However, we won't dig into much detail about its implementation, since it would escape the tutorial's scope.

    How Does the App Work?

    The application is as simple as possible. It has only one Activity, where the user can get the weather by searching a city's name or using the device's current location. The MainActivity calls the MainModel to get an observable LiveData and reacts to it. The MainModel fetches weather data from the MainRepository, and consolidates all data as LiveData. The MainRepository gets its data from multiple sources.

    Running the Sample App

    Download or clone the repository from our GitHub repo and build with Gradle or open it in your IDE. You must also create an OpenWeatherMap account and get a new application ID. Add the application ID on a string resource called openWeather.

    <string name="openWeather">XXXXXXXXXXXXXXX</string> 2. Setting Up a Project

    Since the Architecture Components are still in alpha, you have to include the Google repository, which contains some experimental libraries, in the project's build.gradle.

    allprojects { repositories { // add this repository maven { url 'https://maven.google.com' } } }

    In the module build.gradle, add the following to the dependencies section to add support for LifecyclesLiveData, and ViewModel:

    • compile "android.arch.lifecycle:runtime:1.0.0-alpha5"
    • compile "android.arch.lifecycle:extensions:1.0.0-alpha5"
    • annotationProcessor "android.arch.lifecycle:compiler:1.0.0-alpha5"

    If you're using Kotlin, you must also add or replace the annotationProcessor with kapt, which handles annotation on Kotlin.

    kapt "android.arch.lifecycle:compiler:1.0.0-alpha5"

    To enable kapt, add the following in the module's build.gradle root.

    kapt { generateStubs = true } 3. The Lifecycle Component

    Every Android developer is familiar with the lifecycle concept. The system drives the lifecycle of Applications, Activities, Fragments, and so on, without the control of the developer. This concept is one of Android's paradigms and, until recently, it wasn't that easy to work with, since it wasn't possible to directly check for the current lifecycle status of a component. What we could do was to react to certain methods, like onCreate and onDestroy, triggered by lifecycle events.

    This has all changed since the announcement of the Architecture Components package, which introduced a component called Lifecycle. Now, some Android objects have a Lifecycle attached to them, and this changes lots of things for the developers. It is possible to consult a Lifecycle state at any given time, and it is also possible to react to Lifecycle events using annotations. In fact, the backbone of the new Android Architecture Components is the Lifecycle component.

    All elements of the package android.arch.lifecycle are important to the lifecycle concept, but two of them deserve more attention: LifecycleOwner and LifecycleObserver. They create the possibility of working with Lifecycle, observing as well as reacting to events that occur on Activities, Fragments, Services and so on.

    The LifecycleOwner

    The LifecycleOwner is a single method interface for classes that contain a Lifecycle. It abstracts the possession of a Lifecycle, allowing you to write components that can work with it. By the new standards, Activities and Fragments are LifecycleOwners. However, until the final version of the Architecture Components is launched, you must use some special classes: ActivityLifecycle, FragmentLifecycle, and LifecycleService.

    class MainActivity : LifecycleActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } }

    There's no significant change in the implementation of these classes when compared to the standard Activities and Fragments. Once a class extends any of them, it will have a Lifecycle attached, which can be fetched at any time with the method getLifecycle(). Another interesting possibility is that we can check the current lifecycle state with getCurrentState, which returns a Lifecycle.State. 

    There are five different Lifecycle states:

    • INITIALIZED: for an object that has been called, but which isn't "active" yet. It is the equivalent to a state before the Activity.onCreate method.
    • CREATED: for objects that were just created. It is called after the onCreate method and also called just before the onStop method.
    • STARTED: called after the onStart and just before the onPause method.
    • RESUMED: The active state or the resumed state for a LifecycleOwner. Called after the onResume method.
    • DESTROYED: for a destroyed LifecycleOwner object. This Lifecycle won't dispatch more events. This event is reached right before the onDestroy method.
    The LifecycleObserver

    One of the most interesting properties of the Lifecycle is that it can easily be observed.  LifecycleObserver classes can observe LifecycleOwner components, like Activities and Fragments. It receives LifecycleOwner.Events, and can react to them through the annotation @OnLifeCycleEvent( Lifecycle.Event ).

    class MainObserver : LifecycleObserver, AnkoLogger { @OnLifecycleEvent( Lifecycle.Event.ON_RESUME ) fun onResult() { info("onResult") } @OnLifecycleEvent( Lifecycle.Event.ON_STOP ) fun onStop() { info("onStop") } }

    The methods annotated with @OnLifecycleEvent don't need arguments, but if used, the first argument must be the LifecycleOwner. When the annotation uses Lifecycle.Event.ON_ANY, the method should expect two arguments: LifecycleOwner and Lifecycle.Event.

    @OnLifecycleEvent( Lifecycle.Event.ON_ANY ) fun onEvent( owner: LifecycleOwner, event: Lifecycle.Event ) { info("onEvent: ownerState: ${owner.lifecycle.currentState}") info("onEvent: event: $event") }

    To activate the @OnLifecycleEvent annotation, the LifecycleObserver must be observing a Lifecycle, otherwise it won't receive the event. To make this work, call Lifecycle.addObserver(LifecycleOwner) and the LifecycleOwner will subsequently be able to react to Lifecycle.Event. It is also possible to call Lifecycle.removeObsever(LifecycleObserver) to remove an observer.

    class MainActivity : LifecycleActivity(), AnkoLogger { @Inject lateinit var mainObserver: MainObserver override fun onCreate(savedInstanceState: Bundle?) { // ... // On Kotlin, instead of getLifecycle, // we can call lifecycle directly lifecycle.addObserver( mainObserver ) } override fun onDestroy() { // ... lifecycle.removeObserver( mainObserver ) } }

    There are various interesting use-cases for LifecycleObserver. For example, it could be used to create a Presenter layer from the Model View Presenter architecture pattern. It could also be used to create listeners that can stop listening when the Lifecycle is disabled.

    4. The LiveModel Component

    Designed to work together with the UI layer, the ViewModel component closes a gap that has existed in Android since the beginning: providing a way to elegantly manage and store data objects related to the view. The component maintains data integrity between configuration changes, can be shared between Activity and Fragments, and is an excellent tool to completely avoid memory leaks.

    The ViewModel is always created in close relation to a specific scope, either an Activity or Fragment. The scope is retained as long as the Activity or Fragment is alive. In practical terms, the ViewModel reconnects with the view after configuration changes, maintaining itself until the main view is destroyed. According to the official documentation:

    The purpose of the ViewModel is to acquire and keep the information that is necessary for an Activity or a Fragment.

    On top of all that, the ViewModel facilitates the separation of concerns in the Android development process. By moving all the data-related operations to this component and letting it handle the logic, the application testability and maintainability is greatly increased. With ViewModel, it's possible to easily adopt the Android Architecture proposed at the 2017 Google I/O. You can even use it to adopt more sophisticated architecture patterns, like MVP or MVVM.

    Implementing a ViewModel

    There are two ways to implement a ViewModel. The standard one is to extend the class, providing a no-argument constructor. This is the easiest way, but it doesn't work well with Dependency Injection.

    class MainViewModel : ViewModel() { init { // initialize some behavior } fun getData() : LiveData<String> { // get some data } override fun onCleared() { super.onCleared() // called before its destruction } }

    To get a ViewModel constructed with this technique from an Activity or Fragment, simply call ViewModelProviders.of(FragmentActivity).get(Class<T>). The last argument must contain the ViewModel class. The same ViewModel instance will be fetched by the view and will contain all the data for that view.

    val viewModel: MainViewModel = ViewModelProviders.of(this).get(MyViewModel::class.java)

    Notice that, since the ViewModel is taken from ViewModelProviders.of method, its constructor cannot receive arguments. As a workaround, you can implement a ViewModelProvider.Factory. Actually, this is the same technique we use to inject ViewModel.

    Injecting a ViewModel

    When using DI, things get a little trickier. You'll need to implement a ViewModelProvider.Factory. The following steps can be used to inject a ViewModel using Dagger. The ViewModelFactory is a utility class that provides a ViewModel for a scope.

    @Suppress("UNCHECKED_CAST") @Singleton class ViewModelFactory @Inject constructor( private val creators: Map<Class<out ViewModel>, @JvmSuppressWildcards Provider<ViewModel>> ) : ViewModelProvider.Factory { override fun <T : ViewModel> create(modelClass: Class<T>): T { var creator: Provider<out ViewModel>? = creators[modelClass] if (creator == null) { for ((key, value) in creators) { if (modelClass.isAssignableFrom(key)) { creator = value break } } } if (creator == null) { throw IllegalArgumentException("unknown model class " + modelClass) } try { return creator.get() as T } catch (e: Exception) { throw RuntimeException(e) } } }

    Dagger also needs a @MapKey defined for ViewModel and a binder for each model and for the factory in the module.

    // @MapKey @MustBeDocumented @Target( AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER ) @kotlin.annotation.Retention() @MapKey internal annotation class ViewModelKey( val value: KClass<out ViewModel>) // ViewModel Module @Module abstract class ViewModelsModule { // Bind each ViewModel @Binds @IntoMap @ViewModelKey( MainViewModel::class ) abstract fun bindMainViewModel( mainViewModel: MainViewModel ) : ViewModel // ViewModel factory binding @Binds abstract fun bindViewModelFactory( factory: ViewModelFactory ) : ViewModelProvider.Factory }

    After that, follow the standard Dagger procedures and you'll be able to create a ViewModel capable of injecting arguments on its constructor. To create a new instance, get the ViewModelFactory and take the desired ViewModel from it.

    // Get the ViewModel factory @Inject lateinit var viewModelFactory: ViewModelProvider.Factory // Get ViewModel val viewModel = ViewModelProviders.of(this, viewModelFactory) .get(MainViewModel::class.java)

    In our sample project, you can take a close look at DI using Dagger. I've also provided you with a folder of examples in the tutorial GitHub repo with snippets showing how to configure ViewModels on the Dagger system using Kotlin.

    class MainViewModel @Inject constructor( private val repository: MainRepository ) : ViewModel(), AnkoLogger { // ... code goes here }Conclusion

    So far, our journey through the new Android Architecture Components has been very productive. However, we still have some ground to cover. In the next tutorial, we’ll talk about the awesome LiveData component, investigating its basic and advanced features, and applying these concepts to our sample application.

    See you soon! And in the meantime, check out some of our other posts on Android app development!

    6 days 12 hours ago

Pages