How to develop an Android App in 2019: embracing the ‘new‘ Android

There‘s never been a better time to get into Android app development. In the past few years, Android development has undergone a renaissance, with the introduction of a modern programming language (Kotlin), reusable architecture components (Jetpack), and a more opinionated approach to app structure (single activity architecture). Google has doubled down on its investment into making Android development more efficient, expressive and enjoyable.

As an Android developer who started just a few years ago during the Java 6 era, I‘ve witnessed this evolution firsthand. Android development in 2019 is almost unrecognizable from what it was before. If you tried Android development a while back and found it painful, it‘s worth giving it another shot. Trust me – it‘s gotten a whole lot better.

So what exactly does Android development look like in 2019? Let‘s break it down.

The Language: Kotlin

The biggest change in modern Android development is undoubtedly the rise of Kotlin. Kotlin is a statically typed programming language developed by JetBrains that runs on the Java Virtual Machine. Google announced first-class support for Kotlin on Android at Google I/O 2017, and since then Kotlin has seen meteoric growth in the Android community.

What makes Kotlin so lovable? Where do I begin! Compared to Java, Kotlin is more concise, expressive, and safe. Features like type inference, optional parameters, extension functions, null safety, data classes, and smart casting make Kotlin a joy to write. It‘s fully interoperable with Java, so you can adopt it incrementally in an existing project. In fact, as of Android Studio 3.0, creating a new project with Kotlin support is just a checkbox away.

In 2019, Kotlin is the preferred language for Android development. If you‘re starting a new Android project today, I strongly recommend using Kotlin from the get-go. And if you have an existing Java project, now‘s a great time to start sprinkling in some Kotlin. Trust me, you‘ll thank yourself later.

The Libraries: Jetpack & AndroidX

Jetpack is a suite of libraries and tools developed by Google to help developers follow best practices, reduce boilerplate code, and write code that works consistently across Android versions. Jetpack components are built to work together seamlessly, taking a lot of the guesswork out of architecture.

Some of the most useful Jetpack libraries include:

  • ViewModel: Stores and manages UI-related data in a lifecycle-aware way, surviving configuration changes like screen rotations.

  • LiveData: An observable data holder that notifies views when data changes, ensuring your UI always reflects the current state.

  • Room: An SQLite object mapping library that provides compile-time checks and reduces boilerplate code for working with databases.

  • Navigation: A framework for moving between ‘destinations‘ within an app, with a focus on making complex navigation patterns simple.

  • WorkManager: Makes it easy to schedule deferrable, asynchronous tasks (like uploading logs) that are expected to run even if the app exits or the device restarts.

These are just a few of the many Jetpack libraries available. What‘s great is that you can adopt them incrementally – you don‘t have to go all in on Jetpack from day one.

In addition to Jetpack, Google has released AndroidX, which is a major improvement to the original Android Support Library. AndroidX packages feature concise naming and strict versioning, making dependency management a lot cleaner.

In 2019, Jetpack and AndroidX are must-haves for Android development. They embody the modern, opinionated Android development experience that Google is promoting. Adopting these libraries will make your life as a developer much easier.

The Architecture: MVVM & Single Activity

With the introduction of architecture components like ViewModel and LiveData, Google is heavily pushing the Model-View-ViewModel (MVVM) architecture pattern for building Android apps.

MVVM separates your app into three layers:

  • Model: Represents the data and business logic of your app. This includes local databases, web services, repositories, etc.

  • View: Displays the UI and receives user interactions. In Android, views are typically fragments and activities.

  • ViewModel: Acts as a bridge between the model and the view. It transforms model data into values that can be displayed on a view, and it updates the model based on user actions.

The key benefit of MVVM is that it decouples your views from your model, making your code more modular and testable. ViewModels survive configuration changes, so you no longer have to worry about storing and restoring UI state manually. And with data binding, you can replace a lot of tedious UI callbacks with declarative bindings.

Traditionally, navigation between screens in Android has been done using activities. Each screen would be represented by an activity, and you‘d start new activities to move between screens.

However, the single activity architecture has been gaining traction as the preferred approach for modern Android apps. With the single activity architecture, there‘s only one activity that acts as the entry point for your app. Navigation is instead handled by fragments, using the Navigation component.

The benefits of the single activity architecture are numerous:

  • It simplifies navigation code, as fragments can simply use the built-in NavController to navigate between destinations.

  • It reduces coupling between screens, as fragments don‘t need to know about each other directly.

  • It makes animating transitions between screens a lot easier.

  • It enables deep linking to any destination in your app, not just activities.

In 2019, MVVM and single activity architecture are the recommended patterns for structuring your Android app. They work hand-in-hand with architecture components to create a more maintainable and testable codebase.

Putting It All Together

Alright, enough with the concepts – let‘s see what a modern Android app actually looks like in practice!

Imagine we‘re building a simple news reader app. The app has three screens: a list of top stories, a detail view for each story, and a webview for viewing the full article.

Here‘s what the project structure might look like using MVVM and a single activity architecture:

/app
    /data
        /model
            NewsArticle.kt
        /remote
            NewsService.kt 
        /repo
            NewsRepository.kt
    /di
        AppComponent.kt
        AppModule.kt
        ViewModelModule.kt  
    /ui  
        /article
            ArticleFragment.kt
            ArticleViewModel.kt
        /list
            ListAdapter.kt 
            ListFragment.kt
            ListViewModel.kt
        /reader  
            ReaderFragment.kt
            ReaderViewModel.kt
        MainActivity.kt
    AppNavigator.kt  

There‘s a lot going on here, so let‘s break it down:

  • data/ contains our models (NewsArticle), our remote data source (NewsService), and our repository (NewsRepository) which combines multiple data sources.

  • di/ contains dependency injection-related classes using Dagger. This is where we create our graph of dependencies (retrofit services, database DAOs, view models, etc.)

  • ui/ contains our fragments and their corresponding ViewModels. Each screen is represented by a fragment, and each fragment has its own ViewModel that survives configuration changes.

  • AppNavigator is a custom class that uses the Navigation component to handle app navigation.

  • MainActivity is our single activity that hosts the navigation graph.

Here‘s what a typical fragment (e.g. ListFragment) might look like with this architecture:

class ListFragment : Fragment() {

    private val viewModel: ListViewModel by viewModel()

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        val binding = FragmentListBinding.inflate(inflater, container, false)
        context ?: return binding.root

        val adapter = ListAdapter()
        binding.recyclerView.adapter = adapter
        subscribeUi(adapter)

        return binding.root
    }

    private fun subscribeUi(adapter: ListAdapter) {
        viewModel.articles.observe(viewLifecycleOwner, Observer { articles ->
            adapter.submitList(articles)
        })
    }
}

And here‘s what the corresponding ViewModel (ListViewModel) might look like:

class ListViewModel @Inject constructor(
    private val newsRepository: NewsRepository
) : ViewModel() {

    val articles = newsRepository.getTopArticles()
}

This is just a small taste of what a modern Android app looks like, but it demonstrates the power of combining Kotlin, architecture components, and dependency injection.

The fragment is concise and focused on UI concerns. It observes LiveData from the ViewModel and updates the UI accordingly. The ViewModel is also concise, focused solely on providing the data needed for the UI. And the Repository layer abstracts away the details of fetching data, allowing the ViewModel to remain simple.

Best Practices & Testing

Of course, there‘s more to building a high-quality Android app than just using the right libraries and architecture. Following best practices and writing tests are just as important for maintaining a healthy codebase.

Some key best practices to follow in a modern Android app:

  • Organize your code into feature packages, not layers. Instead of having top-level data, ui, util packages, organize by feature (e.g. article, list, reader). This makes your code more modular and easier to navigate.

  • Minimize dependencies between packages. Use dependency injection (e.g. with Dagger or Koin) to provide dependencies and keep packages loosely coupled.

  • Keep your ViewModels focused. ViewModels should only contain logic for preparing data for the UI. Avoid putting navigation logic, complex business logic, or framework dependencies in ViewModels.

  • Prefer single-responsibility classes. Each class should have a single, well-defined responsibility. This makes your code more testable and easier to understand.

  • Use dependency injection to make your code more testable. Injecting dependencies (as opposed to instantiating them directly) allows you to easily swap in mock implementations in tests.

Speaking of tests, a modern Android app should have a robust test suite. Unit testing your ViewModel layer is a great place to start, as it doesn‘t require any Android dependencies and can be run quickly on a local JVM.

Use a testing framework like JUnit and a mocking library like Mockito to write concise and maintainable unit tests. Aim for high coverage of your ViewModels and business logic.

UI testing is notoriously challenging on Android, but libraries like Espresso and the new AndroidX Test library make it a lot more manageable. Focus on writing black box integration tests that verify key user flows in your app.

Staying Up-to-Date

Android development is evolving at a rapid pace. Just in the past year, we‘ve seen the rise of Kotlin coroutines for asynchronous programming, the CameraX library for easier camera development, the Jetpack Compose framework for declarative UI, and much more.

Staying up-to-date with the latest trends is crucial for being an effective Android developer. Some resources I recommend for staying in the loop:

  • Android Weekly: A weekly newsletter rounding up the latest Android development news and articles.
  • Android Developers Blog: The official source for Android development news straight from Google.
  • Google I/O: Google‘s annual developer conference, where they announce the latest updates to Android and other Google technologies. Definitely worth watching the Android-related talks each year.
  • Android Dev Summit: A smaller Android-focused conference with deep dives into Android development topics.
  • Kotlin Weekly: A weekly newsletter for Kotlin developers, often featuring Android-related articles.

Following Android thought leaders on Twitter and Medium is also a great way to stay plugged into the community.

Wrapping Up

Android development has come a long way in the past few years. With Kotlin, architecture components, and an emphasis on best practices, it‘s never been a better time to be an Android developer.

If you‘re new to Android development, don‘t be intimidated by all the new technologies and terminologies. Start with the basics – learn Kotlin, understand the Android lifecycle, and practice building simple apps using MVVM and the core Architecture Components.

Once you have a solid foundation, start layering on more advanced concepts like coroutines, dependency injection, and modularization. And don‘t forget to write tests!

Most importantly, enjoy the process. Android development can be challenging, but it‘s also incredibly rewarding. With the power of Android, you have the opportunity to reach billions of users and make a real impact on their lives.

So what are you waiting for? Go forth and build something amazing!

Similar Posts