Tag Archives: #11WeeksOfAndroid

What’s New in Navigation 2020

Posted by Jeremy Woods, Software Engineer, Android UI Toolkit

Navigation image

The latest versions of the Jetpack Navigation library (2.2.0 and 2.3.0) added a lot of requested features and functionality, including dynamic navigation, navigation back stack entries, a library for navigation testing, additional features for deep linking, and more. Let’s go over the most important changes, see what problems they solve, and learn how to use them!

Dynamic Navigation

We’ve updated Navigation to simplify adding dynamic feature modules for your application.

Previously, implementing navigation between destinations defined in dynamic feature modules required a lot of work. Before you could navigate to the first dynamic destination, you needed to add the Play Core library and the Split Install API to your app. You also needed to check for and download the dynamic module. Once downloaded, you could then finally navigate to the destination. On top of this, if you wanted to have an on-screen progress bar for the module being downloaded, you needed to implement a SplitInstallManager listener.

To address this complexity, we created the Dynamic Navigator library. This library extends the functionality of the Jetpack Navigation library to provide seamless installation of on-demand dynamic feature modules when navigating. The library handles all Play Store interaction for you, and it even includes a progress screen that provides the download status of your dynamic module.

The default UI for showing a progress bar when a user navigates to a dynamic feature for the first time.

The default UI for showing a progress bar when a user navigates to a dynamic feature for the first time. The app displays this screen as the corresponding module downloads

To use dynamic navigation, all you need to do is:

  1. Change instances of NavHostFragment to DynamicNavHostFragment
  2. Add an app:moduleName attribute to the destinations associated with a DynamicNavHostFragment

For more information on dynamic navigation, see Navigate with dynamic feature modules and check out the samples.

NavBackStackEntry: Unlocked

When you navigate from one destination to the next, the previous destination and its latest state is placed on the Navigation back stack. If you return to the previous destination by using navController.popBackBack(), the top back stack entry is removed from the back stack with its state still intact and the NavDestination is restored. The Navigation back stack contains all of the previous destinations that were needed to arrive at the current NavDestination.

We manage the destinations on the Navigation back stack by encapsulating them into the NavBackStackEntry class. NavBackStackEntry is now public. This means that users can go a level deeper than just NavDestinations and gain access to navigation-specific ViewModels, Lifecycles, and SavedStateRegistries. You can now properly scope data sharing or ensure it is destroyed at the appropriate time.

See Navigation and the back stack for more information.

NavGraph ViewModels

Since a NavBackStackEntry is a ViewModelProvider, you can create a ViewModel to share data between destinations at the NavGraph level. Each parent navigation graph of all NavDestinations are on the back stack, so your view model can be scoped appropriately:

val viewModel: MyViewModel by navGraphViewModels(R.id.my_graph)

For more information on navGraph scoped view models, see Share UI-related data between destinations with ViewModel

Returning a Result from a destination

By combining ViewModel and Lifecycle, you can share data between two specific destinations. To do this, NavBackStackEntry provides a SavedStateHandle, a key-value map that can be used to store and retrieve data, even across configuration changes. By using the given SavedStateHandle, you can access and pass data between destinations. For example to pass data from destination A to destination B:

In destination A:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    val navController = findNavController();
    // We use a String here, but any type that can be put in a Bundle is supported
    navController.currentBackStackEntry?.savedStateHandle?.getLiveData<String>("key")?.observe(
        viewLifecycleOwner) { result ->
        // Do something with the result.
    }
}

And in destination B:

navController.previousBackStackEntry?.savedStateHandle?.set("key", result)

See Returning a result to the previous Destination for more details.

Testing your Navigation Flow

Previously, the recommended testing solution for Navigation was Mockito. You would create a mock NavController and verify that navigate() was called at the appropriate time with the correct parameters. Unfortunately, this solution was not enough to test certain areas of Navigation flow, such as ViewModel interaction or the Navigation back stack. The Navigation Library now offers a well-integrated solution for these areas with the Navigation Testing library.

The Navigation Testing library adds TestNavHostController, which gives access to the Navigation back stack in a test environment. This means that you can now verify the state of the entire back stack. When using the TestNavHostController, you can set your own LifecycleOwner, ViewModelStoreOwner, and OnBackPressDispatcher by using the APIs given by NavHostController. By setting these components, you can test them in the context of navigation.

For example, here's how to test a destination that uses a nav graph-scoped ViewModel:

val navController = TestNavHostController(ApplicationProvider.getApplicationContext())

// This allows fragments to use by navGraphViewModels()
navController.setViewModelStore(ViewModelStore())
navController.setGraph(R.navigation.main_nav)

The TestNavHostController also lets you set the current destination. You can move the test directly to the use case being tested without the need to set it up using navigate() calls. This is extremely convenient for writing tests for different navigation scenarios.

When setting the current destination, you might do something like the following:

val navController = TestNavHostController(ApplicationProvider.getApplicationContext())

navController.setGraph(R.navigation.main_nav)
navController.setCurrentDestination(R.id.destination_1)

Remember that when setting the current destination, that destination must be part of your nav graph.

For more information about TestNavHostController, see the Test Navigation docs.

Nav Deep Linking

Deep linking allows you to navigate directly to any destination no matter where you currently are in the NavGraph. This can be very useful for launching your app to a specific destination or jumping between destinations that would otherwise be inaccessible to one another.

When navigating using a deep link, you can now provide deep link query parameters in any order and even leave them out altogether if they have been given a default value or have been made nullable. This means that if you have provided default values for all of the query parameters on a deep link, the deep link can match a URL pattern without including any query parameters.

For example, www.example.com?arg1={arg1}&arg2={arg2} will now match with www.example.com as long as arg1 and arg2 have default values and/or are nullable.

Deep links can also be matched using intent actions and MIME types. Instead of requiring destinations to match by URI, you can provide the deep link with an action or MIME type and match with that instead. You can specify multiple match types for a single deep link, but note that URI argument matching is prioritized first, followed by action, and then mimeType.

You create a deep link by adding it to a destination in XML, using the Kotlin DSL, or by using the Navigation Editor in Android Studio.

Here's how to add a deep link to a destination using XML:

<fragment android:id="@+id/a"
          android:name="com.example.myapplication.FragmentA"
          tools:layout="@layout/a">
        <deeplink app:url="www.example.com"
                app:action="android.intent.action.MY_ACTION"
                app:mimeType="type/subtype"/>
    </fragment>

Here's how to add the same deep link using the Kotlin DSL:

val baseUri = "http://www.example.com/"

fragment<MyFragment>(nav_graph.dest.a) {
   deepLink(navDeepLink {
    uriPattern = "${baseUri}"
    action = "android.intent.action.MY_ACTION"
    mimeType = "type/subtype"
   })
}

You can also add the same deep link using the Navigation Editor in Android Studio versions 4.1 and higher. Note that you must also be using the Navigation 2.3.0-alpha06 dependency or later.

An open dialog in the Navigation Editor for adding a deep link to a destination. There are options to add an URI, a MIME type, and an action, along with a checkBox to Auto Verify

Adding a deep link to a destination in the Navigation Editor

To navigate to a destination using a deep link, you must first build a NavDeepLinkRequest and then pass that deep link request into the Navigation controller's call to navigate():

val deepLinkRequest = NavDeepLinkRequest.Builder
        .fromUri(Uri.parse("http://www.example.com"))
        .setAction("android.intent.action.MY_ACTION")
        .setMimeType("type/subtype")
        .build()
navController.navigate(deeplinkRequest)

For more information on deep links, visit Create a deep link for a destination, as well as the deep linking sections in Navigate to a destination and Kotlin DSL.

Navigation Editor

Android Studio 4.0 includes new features for the Navigation Editor. You can now edit your destinations using a split pane view. This means you can edit the XML or design and see the changes in real time.

The Navigation Editor opened in split pane mode with the navigation.xml file on the left and the corresponding nav graph on the right. The nav graph has 6 destination, and a nested graph

Viewing a navigation.xml file in split view mode

In Android Studio 4.1, the Navigation Editor introduced the component tree. This allows you to traverse the entire nav graph, freely going in and out of nested graphs.

An open component tree of a nav graph in the Navigation Editor. It starts viewing the entire graph, then moves to the title screen before going into the nested profiles graph. After cycling through the destinations in the profiles graph, it goes back to fragments in the original graph

Navigating through a graph in the Navigation Editor

Additional Changes

NavigationUI can now use any layout that uses the Openable interface. This means that it is no longer limited to DrawerLayout and allows for customization of the AppBarConfiguration. You can provide your Openable and use it as the layout instead.

Navigation also provides support for Kotlin DSL. Kotlin DSL can be used to create different destinations, actions, or deep links. For more information see the documentation for Kotlin DSL.

Wrap up

Navigation added lots of useful features over the past year. You can simplify your dynamic feature modules by taking advantage of the Dynamic Navigator library, use a NavBackStackEntry to help correctly scope your data, easily test your navigation flow using the TestNavHostController, or even match your deep link using intent actions and/or MIME types.

For more information about the Jetpack Navigation library, check out the documentation at https://developer.android.com/guide/navigation

Please provide feedback (or file bugs) using the Navigation issuetracker component.

Getting on the same page with Paging 3

Posted by Florina Muntenescu, Android Developer Advocate

Android graphic

Getting on the same page with Paging 3

The Paging library enables you to load large sets of data gradually and gracefully, reducing network usage and system resources. You told us that the Paging 2.0 API was not enough - that you wanted easier error handling, more flexibility to implement list transformations like map or filter, and support for list separators, headers, and footers. So we launched Paging 3.0 (now in alpha02), a complete rewrite of the library using Kotlin coroutines (still supporting Java users) and offering the features you asked for.

Paging 3 highlights

The Paging 3 API provides support for common functionality that you would otherwise need to implement yourself when loading data in pages:

  • Keeps track of the keys to be used for retrieving the next and previous page.
  • Automatically requests the correct next page when the user scrolls to the end of the loaded data.
  • Ensures that multiple requests aren’t triggered at the same time.
  • Tracks loading state and allows you to display it in a RecyclerView list item or elsewhere in your UI, and provides easy retry functionality for failed loads.
  • Enables common operations like map or filter on the list to be displayed, independently of whether you’re using Flow, LiveData, or RxJava Flowable or Observable.
  • Provides an easy way of implementing list separators.
  • Simplifies data caching, ensuring that you’re not executing data transformations at every configuration change.

We also made several Paging 3 components backwards compatible with Paging 2.0; so if you already use Paging in your app, you can migrate incrementally.

Adopting Paging 3 in your app

Let’s say that we’re implementing an app that displays all the good doggos. We get the doggos from a GoodDoggos API that supports index-based pagination. Let’s go over the Paging components we need to implement and how they fit into your app architecture. The following examples will be in Kotlin, using coroutines. For examples in the Java programming language using LiveData/RxJava, check out the documentation.

The Paging library integrates directly into the recommended Android app architecture in each layer of your app:

Paging components

Paging components and their integration in the app architecture"

Defining the data source

Depending on where you’re loading data from, implement only a PagingSource or a PagingSource and a RemoteMediator:

  • If you’re loading data from a single source, like network, local database, a file, etc, implement the PagingSource (if you’re using Room, it implements the PagingSource for you starting in Room 2.3.0-alpha).
  • If you’re loading data from a layered source, like a network data source with a local database cache, implement the RemoteMediator to merge the two sources and a PagingSource for the local database cache.

PagingSource

A PagingSource defines the source of paging data and how to retrieve data from that single source. The PagingSource should be part of the repository layer. Implement load() to retrieve paged data from your data source and return the loaded data together with information about next and previous keys. This is a suspend function, so you can call other suspend functions here, such as the network call:

class DoggosRemotePagingSource(
    val backend: GoodDoggosService
) : PagingSource<Int, Dog>() {
  override suspend fun load(
    params: LoadParams<Int>
  ): LoadResult<Int, Dog> {
    try {
      // Load page 1 if undefined.
      val nextPageNumber = params.key ?: 1
      val response = backend.getDoggos(nextPageNumber)
      return LoadResult.Page(
        data = response.doggos,
        prevKey = null, // Only paging forward.
        nextKey = response.nextPageNumber + 1
      )
    } catch (e: Exception) {
        // Handle errors in this block
        return LoadResult.Error(exception)
    }
  }
}

PagingData and Pager

The container for paginated data is called PagingData. A new instance of PagingData is created every time your data is refreshed. To build a stream of PagingData create a Pager instance, using a PagingConfig configuration object and a function that tells the Pager how to get an instance of your PagingSource implementation.

In your ViewModel you construct the Pager object and expose a Flow<PagingData> to the UI. Flow<PagingData> has a handy cachedIn() method that makes the data stream shareable and allows you to cache the content of a Flow<PagingData> in a CoroutineScope. That way if you implement any transformations on the data stream, they will not be triggered again each time you collect the flow after Activity recreation. The caching should be done as close to the UI layer as possible, but not in the UI layer, as we want to make sure it persists beyond configuration change. The best place for this would be in a ViewModel, using the viewModelScope:

val doggosPagingFlow = Pager(PagingConfig(pageSize = 10)) {
  DogRemotePagingSource(goodDoggosService)
}.flow.cachedIn(viewModelScope)

PagingDataAdapter

To connect a RecyclerView to the PagingData, implement a PagingDataAdapter:

class DogAdapter(diffCallback: DiffUtil.ItemCallback<Dog>) :
  PagingDataAdapter<Dog, DogViewHolder>(diffCallback) {
  override fun onCreateViewHolder(
    parent: ViewGroup,
    viewType: Int
  ): DogViewHolder {
    return DogViewHolder(parent)
  }

  override fun onBindViewHolder(holder: DogViewHolder, position: Int) {
    val item = getItem(position)
    if(item == null) {
      holder.bindPlaceholder()
    } else {
      holder.bind(item)
    }
  }
}

Then, in your Activity/Fragment you’ll have to collect the Flow<PagingData> and submit it to the PagingDataAdapter. This is what the implementation would look like in an Activity onCreate():

val viewModel by viewModels<DoggosViewModel>()

val pagingAdapter = DogAdapter(DogComparator)
val recyclerView = findViewById<RecyclerView>(R.id.recycler_view)
recyclerView.adapter = pagingAdapter

lifecycleScope.launch {
  viewModel.doggosPagingFlow.collectLatest { pagingData ->
    pagingAdapter.submitData(pagingData)
  }
}

Paged data transformations

A filtered list

Displaying a filtered list

Transforming PagingData streams is very similar to the way you would any other data stream. For example, if we only want to display playful doggos from our Flow<PagingData<Dog>> we would need to map the Flow object and then filter the PagingData:

doggosPagingFlow.map { pagingData ->
        pagingData.filter { dog -> dog.isPlayful }
    }
list with separators

List with separators

Adding list separators is also a paged data transformation where we transform the PagingData to insert separator objects into the list. For example, we can insert letter separators for our doggos’ names. When using separators, you will need to implement your own UI model class that supports the new separator items. To modify your PagingData to add separators, you will use the insertSeparators transformation:

pager.flow.map { pagingData: PagingData<Dog> ->
  pagingData.map { doggo ->
    // Convert items in stream to UiModel.DogModel.
    UiModel.DogModel(doggo)
  }
  .insertSeparators<UiModel.DogModel, UiModel> { before: Dog, after: Dog ->
      return if(after == null) {
          // we're at the end of the list
          null
      }  
      if (before == null || before.breed != after.breed) {
          // breed above and below different, show separator
          UiModel.SeparatorItem(after.breed)
       } else {
           // no separator
           null
       }
    }
  }
}.cachedIn(viewModelScope)

Just as before, we're using cachedIn right before the UI layer. This ensures that loaded data and the results of any transformations can be cached and reused after a configuration change.

Advanced Paging work with RemoteMediator

If you’re paging data from a layered source, you should implement a RemoteMediator. For example, in the implementation of this class you need to request data from the network and save it in the database. The load() method will be triggered whenever there is no more data in the database to be displayed. Based on the PagingState and the LoadType we can construct the next page request.

It’s your responsibility to define how the previous and next remote page keys are constructed and retained as the Paging library doesn’t know what your API looks like. For example, you can associate remote keys to every item you receive from the network and save them in the database.

override suspend fun load(loadType: LoadType, state: PagingState<Int, Dog>): MediatorResult {

   val page = ... // computed based on loadType and state

   try {
       val doggos = backend.getDoggos(page)
       doggosDatabase.doggosDao().insertAll(doggos)
       
       val endOfPaginationReached = emails.isEmpty()
       return MediatorResult.Success(endOfPaginationReached = endOfPaginationReached)
   } catch (exception: Exception) {
       return MediatorResult.Error(exception)
   } 
}

When you’re loading data from the network and saving it to the database, the database is the source of truth for the data displayed on the screen. This means that the UI will be displaying data from your database, so you’ll have to implement a PagingSource for your database. If you’re using Room, you’ll just need to add a new query in your DAO that returns a PagingSource:

@Query("SELECT * FROM doggos")
fun getDoggos(): PagingSource<Int, Dog>

The Pager implementation changes slightly in this case, as you need to pass the RemoteMediator instance as well:

val pagingSourceFactory = { database.doggosDao().getDoggos() }

return Pager(
     config = PagingConfig(pageSize = NETWORK_PAGE_SIZE),
     remoteMediator = DoggosRemoteMediator(service, database),
     pagingSourceFactory = pagingSourceFactory
).flow

Check out the docs to find out more about working with RemoteMediator. For a complete implementation of RemoteMediator in an app, check out step 15 of the Paging codelab and the accompanying code.



We’ve designed the Paging 3 library to help you accommodate both simple and complex uses of Paging. It makes it easier to work with large sets of data whether it’s being loaded from the network, a database, in-memory cache, or some combination of these sources. The library is built on coroutines and Flow, making it easy to call suspend functions and work with streams of data.

As Paging 3 is still in alpha, we need your help to make it better! To get started, find out more about Paging in our documentation and try it out by taking our codelab or checking out the sample. Then, let us know how we can improve the library by creating issues on the Issue Tracker.

11 Weeks of Android: Languages

Posted by David Winer, Product Manager

11 Weeks of Android, Week 5: Languages

This blog post is part of a weekly series for #11WeeksOfAndroid. Each week we’re diving into a key area of Android so you don’t miss anything. This week, we spotlighted languages; here’s a look at what you should know.

Modern Android development starts with outstanding language support. Together, Kotlin, the Java programming language, and C++ form the foundation for Android’s APIs and the tools you use every day for app development. This week we dove into all of the latest news across Android’s three core languages: from Kotlin coroutines to Android 11’s new Java APIs to better tools for native development, there’s a lot packed into the latest release.

Kotlin and coroutines

Kotlin is at the core of Android’s modern, opinionated APIs. We hear from Android developers around the world that they love Kotlin for how expressive it is, how it helps you write higher quality apps, and how easy it is to start using in your existing Java codebase. More than 70% of the top 1000 apps on the Play Store now use Kotlin, and SlashDataTM announced earlier this year that Kotlin has been the fastest growing language community in percentage terms over the past two years. With the Android 11 beta, we decided to further embrace Kotlin by officially recommending coroutines for asynchronous work on Android.

Coroutines make it easy to write, read, and understand async code. The coroutines library is stable and already has deep integration with many of the Jetpack libraries you may be using, including Room, LiveData, and WorkManager. If you’re new to coroutines, check out Android ❤️ Coroutines: How to Manage Async Tasks in Kotlin, the latest coroutines learning pathway, and our new coroutines developer guide.

Getting started with Kotlin

From Kotlin-first libraries in Android Jetpack to deep integration with the tools in Android Studio, Android is deeply committed to Kotlin — and there’s never been a better time to start using it. We’ve heard from many of you, though, that convincing your team to adopt Kotlin is not always easy. Even though Kotlin is 100% interoperable with the Java programming language, your teammates might have concerns. Is it worth spending the time learning a new language? How should you prioritize Kotlin against our other product and technology priorities?

This week we released a new case study from the Google Home team to help answer some of these questions. Over the course of one year, the Google Home team moved all new feature development to Kotlin and found their null pointer exceptions dropped by 33% during the same period. This is consistent with what we’ve heard from Android teams all over the world — from Duolingo to Zomato to Cash App — Kotlin is delivering value both in the form of productivity and higher app quality for teams large and small. For all our latest case studies and data on Kotlin, check out our new Kotlin case studies page.

For beginners, we announced the launch of our new Android Basics in Kotlin course. If you are just learning how to program, Android Basics teaches essential programming concepts like functions and variables and will take you from “Hello World” all the way up through building a whole collection of Android apps in Kotlin.

The Java programming language and C++

When we announced official support for Kotlin three years ago, we didn’t forget about the large number of Java and C++ Android developers. In the Android 11 release, we sought to keep improving our support for both of these languages. With the Android 11 beta, we upgraded our Java library support with a number of new APIs from OpenJDK 9, 10, and 11. We also unveiled Java library desugaring in Android Studio 4.0, making it easy to use many of these newer Java APIs even on older Android devices — for those of you who have asked for java.time support on older devices, we’ve heard you loud and clear, and it’s arrived. For all the latest information on how to make use of these newer APIs, check out Murat Yener’s talk Support for newer Java APIs. With Android 11, we also updated the Android runtime to make app startup even faster with I/O prefetching.

The C++ developer experience continues to get better, too. Android 11 included updates across the native toolchain, including better tools for profile-guided optimization (PGO) and improvements to native dependency management in Android Studio 4.0.

Ever-improving toolchains

Finally, we continue to focus on improvements to the D8 and R8 compilers in Android Studio. Android Studio comes with built-in support for the R8 shrinker, which helps you keep your app’s memory footprint small, leading to higher installs and retention among your users. We also recently added support for shrinking Kotlin libraries and apps that use Kotlin reflection with R8. For more information, check out Mads Ager and Morten Krogh-Jespersen’s latest Medium post.

Resources

You can find the entire playlist of #11WeeksOfAndroid video content here, and learn more about each week here. We’ll continue to spotlight new areas each week, so keep an eye out and follow us on Twitter and YouTube. Thanks so much for letting us be a part of this experience with you!

Google Home reduces #1 cause of crashes by 33%

The Google Home app helps set up, manage, and control your Google Home, Google Nest, and Chromecast devices—plus thousands of connected home products like lights, cameras, thermostats, and more.

The engineering team behind the Google Home app benefits from using Kotlin and Android Jetpack libraries to boost engineering productivity and developer happiness.

What they did:

The Google Home team decided to incorporate Kotlin into their codebase to make programming more productive and to enable the usage of modern language features like var/val, smart casts, coroutines, and more. As of June 2020, about 30% of the code base is written in Kotlin, and Kotlin development is encouraged for all new features.

The team also adopted Jetpack libraries to improve developer velocity, decrease the need for boilerplate code maintenance, and reduce the necessary amount of code. Jetpack libraries also helped make their code more testable, since there are clearer functional boundaries and APIs.

Results:

"Efficacy and writing less code that does more is the ‘speed’ increase you can achieve with Kotlin.” - Jared Burrows, Software Engineer on Google Home

Switching to Kotlin resulted in a reduction in the amount of required code, compared to the equivalent of existing Java code. One example is the use of data classes and the Parcelize plugin: a class which was 126 hand-written lines in Java can now be represented in just 23 lines in Kotlin—an 80% reduction. Additionally, equality and parcelizing methods can be automatically generated and kept up to date. Many nested loops and filtering checks were also simplified using the functional methods available in Kotlin.

Because Kotlin can make nullability a part of the language, tricky situations can be avoided, like when inconsistent usage of nullability annotations in Java might lead to a missed bug. Since the team started migrating to developing new features with Kotlin, they saw a 33% decrease in NullPointerExceptions. Since this is the most common crash type on Google Play Console, reducing them led to a dramatically improved user experience.

With a large, mature app like Google Home—which has over a million lines of code—it’s helpful to be able to gradually add Jetpack libraries. Incorporating them allowed the team to consolidate and replace custom tailored solutions, sometimes even with a single library. Since Jetpack libraries can help engineers follow best practices and be less verbose (for example, using Room or ConstraintLayout), readability was increased as well. The team considers many of the newer Jetpack libraries ‘must-haves,’ including ViewModel and LiveData, both of which are used extensively in the Google Home codebase.

The Google Home app team found the Jetpack KTX integrations with Kotlin coroutines to be especially helpful. The team is now able to avoid tricky asynchronous programming bugs by associating coroutines with lifecycle-aware components like ViewModel.

Java is a registered trademark of Oracle and/or its affiliates.

Get Started:

Learn more about writing Android apps in Kotlin and using Android Jetpack libraries.

Learn Android and Kotlin with no programming experience

Posted by Kat Kuan, Developer Advocate, Android

Many people today are considering career paths that enable them to work remotely. App development allows for that style of work. For people who want a new opportunity, it’s possible to start learning Android today, even without prior programming experience.

In 2016, we released our Android Basics curriculum, which assumes no programming experience, and the response has been tremendous. Hundreds of thousands of students have been learning Android development and programming concepts simultaneously as they build apps. Since then, there have been big platform changes with four major releases of Android and support added for the Kotlin programming language. We also introduced Jetpack, a suite of libraries that make it easier to build better apps with less code. With all these new updates, it’s time to release the next generation of training content for beginners.

Today we’re announcing the launch of Android Basics in Kotlin, a new online course for people without programming experience to learn how to build Android apps. The course teaches Kotlin, a modern programming language that developers love because of its conciseness and how it increases productivity. Kotlin is quickly gaining momentum in industry. Over a single year from 2018 - 2019, Indeed Hiring Lab found a 76% increase in Kotlin jobs.*

Google announced that Android development is Kotlin-first, and 60% of professional Android developers have already adopted the language. In the Play Store, 70% of the top 1,000 apps use Kotlin. To keep pace and prepare for the future, there has never been a more opportune time to learn Android with Kotlin.

Learning to code for the first time can feel intimidating, but it is possible to learn without a technical background. From a recent Stack Overflow Developer Survey, nearly 40% of the professional developers who studied at university did not receive a formal computer science or software engineering degree.

To build your confidence, the Android Basics in Kotlin course offers step-by-step instructions on how to use Android Studio to build apps, as well as how to run them on an Android device (or virtual device). The goal is to expose you to the tools and resources that professional Android developers use. With hands-on practice, you learn the fundamentals of programming. By the end of the course, you will have completed a collection of Android apps to start building a portfolio.

Object detection & tracking gif Text recognition + Language ID + Translate gif

App screenshots from the course

This course is split up into units, where each unit is made up of a series of pathways. At the end of each pathway, there is a quiz to assess what you’ve learned so far. If you pass the quiz, you earn a badge that can be saved to your Google Developer Profile.
Object detection & tracking gif Text recognition + Language ID + Translate gif

Badges you can earn

The course is free for anyone to take. Basic computer literacy and basic math skills are recommended prerequisites. Unit 1 of the course is available today, with more units being released as they become available. If you’ve never built an app before but want to learn how, check out the Android Basics in Kotlin course.

If you already have programming experience, check out the other free training courses we offer in Kotlin:

We can’t wait to see what you build!

*from US tech job postings on Indeed.com

Preparing your Gradle build for package visibility in Android 11


Posted by David Winer, Product Manager

illustration of mobile device with lock
One of the central themes for Android 11 has been protecting user privacy. On Android 10 and earlier, you could query the full set of installed apps using methods like queryIntentActivities(). Often, however, this approach provides much more access than most apps need to implement their functionality. To better protect user privacy, we updated how apps view and interact with other installed apps on Android 11.
To provide better accountability for access to installed apps, apps targeting Android 11 (API level 30) will see a filtered list of installed apps by default. The new <queries> element in your app or library’s Android manifest allows you to describe which other apps you might need to interact with. For more information about this change, check out our Medium post on package visibility in Android 11.

Android Studio and Gradle support

If you are using Android Gradle plugin 4.1+, your tools should work with the new <queries> declaration. However, older versions of the Android Gradle plugin are not aware of this new element. If you add the <queries> element or if you start relying on a library or SDK that supports targeting Android 11, you may encounter manifest merging errors. For example, when building your app you may see the following error in the Build Output Window:
Android resource linking failed /Users/sample/AndroidStudioProjects/MyApp/app/build/intermediates/merged_manifests/debug/AndroidManifest.xml:18: error: unexpected element <queries> found in <manifest>
Alternatively, you may see an error in the Build Output Window that directs you to the Manifest merger logs:
Manifest merger failed with multiple errors, see logs
Upon expanding the Merged Manifest view you would then see an additional error:
Error: Missing 'package' key attribute on element package

Android Gradle plugin fixes

The best solution to deal with these errors is to upgrade to Android Gradle plugin 4.1 Beta.
We know that not everyone is ready to upgrade to the latest version, though, and you may be relying on old versions of Gradle or libraries that aren’t compatible with 4.1.
So, today we issued a set of dot releases for the Android Gradle plugin that are compatible with <queries>:
For example, if you are currently using Android Gradle plugin version 4.0.0, you can upgrade the version in your project-level build.gradle file:
 buildscript {

    repositories {
        google()
        jcenter()
    }

    dependencies {
        // classpath 'com.android.tools.build:gradle:4.0.0'
        classpath 'com.android.tools.build:gradle:4.0.1'
    }
}

For more information on this new feature in Android 11, check out the package visibility documentation and the Android Gradle plugin release notes.

Preparing your Gradle build for package visibility in Android 11


Posted by David Winer, Product Manager

illustration of mobile device with lock
One of the central themes for Android 11 has been protecting user privacy. On Android 10 and earlier, you could query the full set of installed apps using methods like queryIntentActivities(). Often, however, this approach provides much more access than most apps need to implement their functionality. To better protect user privacy, we updated how apps view and interact with other installed apps on Android 11.
To provide better accountability for access to installed apps, apps targeting Android 11 (API level 30) will see a filtered list of installed apps by default. The new <queries> element in your app or library’s Android manifest allows you to describe which other apps you might need to interact with. For more information about this change, check out our Medium post on package visibility in Android 11.

Android Studio and Gradle support

If you are using Android Gradle plugin 4.1+, your tools should work with the new <queries> declaration. However, older versions of the Android Gradle plugin are not aware of this new element. If you add the <queries> element or if you start relying on a library or SDK that supports targeting Android 11, you may encounter manifest merging errors. For example, when building your app you may see the following error in the Build Output Window:
Android resource linking failed /Users/sample/AndroidStudioProjects/MyApp/app/build/intermediates/merged_manifests/debug/AndroidManifest.xml:18: error: unexpected element <queries> found in <manifest>
Alternatively, you may see an error in the Build Output Window that directs you to the Manifest merger logs:
Manifest merger failed with multiple errors, see logs
Upon expanding the Merged Manifest view you would then see an additional error:
Error: Missing 'package' key attribute on element package

Android Gradle plugin fixes

The best solution to deal with these errors is to upgrade to Android Gradle plugin 4.1 Beta.
We know that not everyone is ready to upgrade to the latest version, though, and you may be relying on old versions of Gradle or libraries that aren’t compatible with 4.1.
So, today we issued a set of dot releases for the Android Gradle plugin that are compatible with <queries>:
For example, if you are currently using Android Gradle plugin version 4.0.0, you can upgrade the version in your project-level build.gradle file:
 buildscript {

    repositories {
        google()
        jcenter()
    }

    dependencies {
        // classpath 'com.android.tools.build:gradle:4.0.0'
        classpath 'com.android.tools.build:gradle:4.0.1'
    }
}

For more information on this new feature in Android 11, check out the package visibility documentation and the Android Gradle plugin release notes.

Preparing your Gradle build for package visibility in Android 11


Posted by David Winer, Product Manager

illustration of mobile device with lock
One of the central themes for Android 11 has been protecting user privacy. On Android 10 and earlier, you could query the full set of installed apps using methods like queryIntentActivities(). Often, however, this approach provides much more access than most apps need to implement their functionality. To better protect user privacy, we updated how apps view and interact with other installed apps on Android 11.
To provide better accountability for access to installed apps, apps targeting Android 11 (API level 30) will see a filtered list of installed apps by default. The new <queries> element in your app or library’s Android manifest allows you to describe which other apps you might need to interact with. For more information about this change, check out our Medium post on package visibility in Android 11.

Android Studio and Gradle support

If you are using Android Gradle plugin 4.1+, your tools should work with the new <queries> declaration. However, older versions of the Android Gradle plugin are not aware of this new element. If you add the <queries> element or if you start relying on a library or SDK that supports targeting Android 11, you may encounter manifest merging errors. For example, when building your app you may see the following error in the Build Output Window:
Android resource linking failed /Users/sample/AndroidStudioProjects/MyApp/app/build/intermediates/merged_manifests/debug/AndroidManifest.xml:18: error: unexpected element <queries> found in <manifest>
Alternatively, you may see an error in the Build Output Window that directs you to the Manifest merger logs:
Manifest merger failed with multiple errors, see logs
Upon expanding the Merged Manifest view you would then see an additional error:
Error: Missing 'package' key attribute on element package

Android Gradle plugin fixes

The best solution to deal with these errors is to upgrade to Android Gradle plugin 4.1 Beta.
We know that not everyone is ready to upgrade to the latest version, though, and you may be relying on old versions of Gradle or libraries that aren’t compatible with 4.1.
So, today we issued a set of dot releases for the Android Gradle plugin that are compatible with <queries>:
For example, if you are currently using Android Gradle plugin version 4.0.0, you can upgrade the version in your project-level build.gradle file:
 buildscript {

    repositories {
        google()
        jcenter()
    }

    dependencies {
        // classpath 'com.android.tools.build:gradle:4.0.0'
        classpath 'com.android.tools.build:gradle:4.0.1'
    }
}

For more information on this new feature in Android 11, check out the package visibility documentation and the Android Gradle plugin release notes.

11 Weeks of Android: Android 11 Compatibility


Posted by Dirk Dougherty, Android Developer Relations

This blog post is part of a weekly series for #11WeeksOfAndroid. Each week we’re diving into a key area of Android so you don’t miss anything. This week, we spotlighted Android 11 Compatibility; here’s a look at what you should know.

The big news

With Beta 2 now in the hands of users and developers, Android 11 is moving quickly toward the final release later in Q3. For developers, now is the time to make sure your apps are ready! With that in mind, this week we highlighted some resources that can help you get started with app compatibility testing and use some of the new tools in Android 11. Here’s a quick rundown of topics that we covered.
Platform stability
In Android 11 we added a new release milestone called Platform Stability to clearly signal to developers that all APIs and system behaviors are complete. This week, with Beta 2, Android 11 reached Platform Stability, so it’s a great time to do your final compatibility testing and updates. The Beta 2 and Platform Stability blog post goes into more detail on what this milestone means for developers, and you can also read about it in the Android 11 timeline.
Platform Stability timeline App compatibility
As we talked about in our Beta 2 post this week, Android 11 compatibility means that your app is validated to run properly on Android 11 with all of the functionality and features that users expect. To get started, all you need is your app and a device or emulator running Android 11.
When making sure an app is compatible, the goal is to test your app and make the minimum changes to maintain your app’s functionality on Android 11, then publish the compatible version to users by the Android 11 final release. In most cases you should be able to do this without changing your targetSdkVersion or compiling against the new APIs.
It isn’t just for apps and games either - if you develop SDKs, libraries, tools, or even frameworks, now is the time to test those against Android 11 and release a compatible version. App and game developers using your products could be blocked until they can get your Android 11 compatible versions.
For more details on app compatibility, take a look at the migration guide and the list of behavior changes that could affect your apps.
Tools for testing your apps
We highlighted some new tools for you to use as you get started with compatibility testing. Our blog post “Testing app compatibility in Android 11” went into the details.
First is the compatibility framework, a new feature that helps with managing the platform changes that can affect apps. It provides standard metadata for changes, standard gating based on targetSdkVersion, and standard log output to help you identify a change affecting your app. You can toggle behavioral changes in a debuggable app, either through Developer options in Settings or through adb. This helps you isolate changes and test against them individually.
Isolating regressions across devices and API levels can be time-consuming and complex. Now with Android Studio 4.2, you can run instrumentation tests in parallel across multiple physical or virtual devices at once, then compare all of the results in a single Test Matrix. You can run tests on more devices in less time, and catch issues earlier.
Android Generic System Image (GSI) is a great way to expand your Android 11 testing across a broader set of devices and we’ve released an updated Android GSI codelab to help you get started. Through GSI, you can install a generic version of Android 11 on any unlocked, Treble-compliant device that shipped with Android 9 or higher. This includes not only Pixel devices, but many other popular devices in use across the global Android ecosystem.
App compatibility toggles in Developer options
App compatibility toggles in Developer options.
Ecosystem updates and app compatibility
In our “Accelerating Android updates” blog post, we looked at how we’re continuing to get the latest OS to reach critical mass by expanding Android’s updatability architecture. With technology like Project Treble and Google Play system updates, we can deliver updates across more devices faster, and increase consistency across the ecosystem.
The work we’ve been doing with Project Treble is making it dramatically faster and easier to bring up new versions of Android on new and existing devices. It also makes it possible for device-makers to run their own Developer Preview programs, in some cases in parallel with Android’s own ongoing development. These programs help device makers get their OS updates ready sooner and engage earlier with the Android developer community.
With Google Play system updates (Project Mainline) the goal is to directly update core OS components across devices in the Android ecosystem to improve security, privacy, and consistency across the ecosystem. In Android 11, we’ve added more updatable modules to standardize behaviors in key app-facing areas such as permissions, media, NNAPI, and others.
Other improvements include a Generic Kernel Image (GKI) and Virtual A/B, a new over-the-air update mechanism that combines the benefits of seamless updates with smaller storage requirements. We’re working closely with device makers to bring these to Android 11 devices.
Over time, these will help reduce your development and testing costs to make your app compatible across platform versions and devices.

Taking center stage

A common reason for unexpected app compatibility issues is apps and games depending on Android non-SDK interfaces. In Android 11 we're continuing our long-term effort to move apps to using public APIs instead.
This week we highlighted Excelliance Tech, who recently moved their LeBian SDK away from non-SDK interfaces, toward stable, official APIs. Their collaboration with the Android team also led to a new public API for resource loading that all developers can use - the ResourcesLoader API in Android 11.
Check out the Excelliance Tech story in this blog post.
The Excelliance Tech team.
The Excelliance Tech team.

What to watch

During Android 11 Compatibility week we posted three short videos to help you plan for compatibility and test your apps. View the playlist here.
The video below gives you a quick overview of Android’s annual release timeline and what the phases mean for developers.
Next, here’s a video that introduces the compatibility framework, a new testing and debugging feature for developers in Android 11. It shows what it is, why it is useful, and how to use it. You’ll walk through an example that shows how you’d enable a specific change, test your app with the change, and then look for the log output to help you identify the change that affected the app.
Last, this video takes you through a new feature in Android Studio that lets you run instrumentation tests in parallel on multiple devices. It shows you how to set up a device set, run tests on the devices, and then jump into the Text Matrix to compare and analyze results. It’s a great way to do your app compatibility testing in Android Studio.

Learning path

If you’re looking for an easy way to pick up the highlights of this week, check out the Compatibility pathway. A pathway is an ordered tutorial that allows users to complete a pre-defined module that culminates in a quiz. A badge is awarded to each user who passes the quiz and can be saved to your Google Developer Profile. Test your knowledge about Android 11 Compatibility to earn a limited edition Android 11 Compatibility badge.

Key takeaways

With each release, we’re working to reduce the impact of compatibility testing on your apps. In Android 11, we’ve added new processes, developer tools, and release milestones to make it easier. We hope the resources we provided this week are helpful as you get started with your compatibility testing. Here are this week’s key takeaways for developers:
  1. Android 11 has reached Platform Stability and all app-facing APIs and behaviors are now complete.
  2. App and game developers should start compatibility testing now and release updates by the Android 11 final release later this year.
  3. SDK, library, and tool developers should complete testing and release compatible versions as soon as possible to avoid blocking downstream developers.
  4. New tools and resources are available to help. See below for highlights and visit developer.android.com/11 for complete details.

Resources

You can find the entire playlist of #11WeeksOfAndroid video content here. We’ll continue to spotlight new areas each week, so keep an eye out and follow us on Twitter and YouTube. Below are the links to resources we talked about during Android 11 Compatibility week.
Blog posts
Testing app compatibility in Android 11
Excelliance Tech: moving to new Android APIs for long-term compatibility
Android 11 Beta 2 and Platform Stability
Accelerating Android updates
Videos
Android 11 Compatibility playlist
Android 11 Compatibility week preview
Testing platform changes in Android 11
Testing app compatibility with Android Studio
Platform Stability and the Android release timeline
Codelabs
Installing Android 11 GSI
Learning Paths
Android 11 - Week 4 - Compatibility
Reddit AMA
Android Platform Team AMA
Related documentation
Android 11 timeline
Get Android 11
Android 11 migration guide
Android 11 behavior changes
Testing app compatibility
Non-SDK restrictions in Android 11
Feedback and issues
Android 11 Developer Site

Accelerating Android Updates

Posted by Eddie Hsu (Technical Program Manager), Brent VerWeyst (Product Manager), Maya Ben Ari (Product Manager), Amith Dsouza (Technical Account Manager), Iliyan Malchev (Project Treble Architect)

Over the past few years we’ve introduced new capabilities that enable us to deliver updates more uniformly, quickly, and efficiently to Android devices. These capabilities include:

  • Oreo’s introduction of Project Treble created a system/vendor split for a much cleaner separation of OEM and SoC dependencies from the rest of the code base. This effort sped up the adoption of Android Pie by 2.5X. Every Android device that preloads the Google Play Store has been Treble compliant since that point.
  • In Pie, we started publishing the Generic System Images (GSI) so that developers can use them for app-compat testing on real hardware. Treble compliance means that every device is compatible with our GSIs, even if it does not ship with them. We also worked with our major partners to launch an OEM developer preview program. As a result, we saw a further 1.5X increase in the adoption of Android 10.
  • In Android 10, we started updating components of the OS directly via Google Play system updates (Project Mainline). Mainline provides security and privacy updates for the OS in a way that’s similar to apps – through Google Play. For example, in our most recent deployment, we directly updated 285 million devices with fixes for security vulnerabilities.
  • Google Play is also responsible for updating critical applications and services, such as authentication, push notifications, and Google Play Protect. A good example is the launch of the Exposure Notification API. Exposure Notifications are a tool to help public-health agencies in the fight against COVID-19. The API was deployed in May via Google Play to over 2 billion devices in the space of just 4 weeks.

Android 10 Adoption

Thanks to these efforts, the adoption of Android 10 has been faster than any previous versions of Android. Android 10 was running on 100 million devices 5 months post launch – 28% faster than Android Pie.

Updatability in Android 11

Below are the major themes in updatability this year:

OEM Developer Previews: In Android 11, device makers (OEMs) are continuing their developer previews ahead of the official launch. Seven OEMs have released Developer Preview builds on 13 devices to provide app developers with diverse hardware as they test for compatibility.

Google Play system update: 21 OS components are now updatable, including 9 additions in Android 11 focused on improving privacy, security, and developer consistency across devices. Highlights include an enhanced permissions component that standardizes user and developer access to critical privacy controls on Android devices, a Neural Networks API (NNAPI) component that optimizes performance and guarantees consistent APIs across devices, and a Tethering component for improved interoperability. The new updatable OS components in Android 11 are: Tethering, NNAPI, Cell Broadcast Receiver, adbd, Internet Key Exchange, Media Provider, statsd, WiFi, and SDK extension.

Generic Kernel Image: Our ongoing updatability work extends to the Linux kernel itself, with initiatives such as 6-year LTS support. In Android 11, we are further isolating common code in the Android Linux kernel to create a Generic Kernel Image (GKI) that works across all Android devices, as well as to enable faster security deployments. Stay tuned for a more detailed post on GKI in the coming months.

Virtual A/B: Most OS updates are not delivered via Google Play. Instead, they use separate third-party Over-the-Air (OTA) services that differ among the various OEMs. These services use a mechanism that, while very space efficient, has the disadvantage of being slow to apply, rendering the device inoperable for the duration. To solve this problem, in Android Nougat we launched a mechanism called "A/B OTA" (aka Seamless Updates). A/B OTAs have the advantage of appearing to be near-instant from the user's perspective, since they apply in the background and become active on the next reboot. However, they doubled the amount of storage reserved for the OS itself, limiting adoption among OEMs.

We’ve developed a new OTA mechanism – Virtual A/B – that combines the benefits of the previous two: being seamless from the user's perspective while requiring less storage. We are working closely with our OEM partners to begin implementing Virtual A/B in Android 11 devices, making OTAs as frictionless as possible. Going forward, Virtual A/B will be the only supported OTA mechanism in Android.

Looking to the Future

We’re excited by the increased adoption of Android and are grateful for the close collaborations with our chipset and OEM partners to deploy updates earlier. We continue to work on a number of enhancements in the platform and infrastructure to make it easier for developers and users to benefit from the latest versions of Android.

Reminder that the Android engineering team will host a Reddit AMA today at 12:00PM PST to answer your technical questions about Android 11. See this post for details and to submit your questions.