Rafael Moreno Cesar - Big Nerd Ranch Tue, 19 Oct 2021 17:47:09 +0000 en-US hourly 1 https://wordpress.org/?v=6.5.5 Kotlin Destructuring Declarations and ComponentN https://bignerdranch.com/blog/kotlin-destructuring-declarations-and-componentn/ https://bignerdranch.com/blog/kotlin-destructuring-declarations-and-componentn/#respond Tue, 28 May 2019 10:00:00 +0000 https://nerdranchighq.wpengine.com/blog/kotlin-destructuring-declarations-and-componentn/ Kotlin's destructure syntax isn't magic. In fact, if you take a look at what's happening under the hood it's easy to tell what what Kotlin is doing the support the use of the destructure syntax with the extension and generated function of componentN.

The post Kotlin Destructuring Declarations and ComponentN appeared first on Big Nerd Ranch.

]]>

Kotlin magic shorthand sytax is everywhere! Kotlin provides some useful syntactic sugar to
assign values from your structures to multiple variables at once like in the example below:

val threeStrings = listOf("one", "two", "three")
val (first, second) = exampleList

In this article we’ll go through how that’s possible in Kotlin, and take a look at two
very common places this destructuring syntax can be used.

Destructuring Collections

Using Kotlin’s destructuring syntax on collections, you can avoid assigning the same variables
on mutliple lines like you’d be doing in the example below

Example 1.

val threeStrings = listOf("one", "two", "three")
val first = exampleList[0]
val second = exampleList[1]

With such a handy syntax, you might want to go crazy and pull out all of the values of one
not-such-a-large-collection,

Example 2.

val sixStrings = listOf("one", "two", "three", "four", "five", "six")
val (first, second, third, fourt, fifth, sixth) = exampleList

but you’ll notice if you try the above example, the compiler actually complains and prompts
you with an error of Kotlin: Destructuring declaration initializer of type List<String> must have a 'component6()' function.

What gives!? Why doesn’t the code compile, and why does the error prompt you to call some component6()
function if it worked for getting the elements you wanted in your previous example? To see
what’s going on, let’s look at what the Kotlin compiler is doing when it compiles the code down in Example 1.

val first = threeStrings.component1
val second = threeStrings.component2

Here you see your first clue into figuring out why you get the mysterious error.
The first thing you might note here is that Kotlin has converted your short hand syntax into
a long form. However, instead of indexing the list in a way you might be used to seeing, such
as threeStrings[0], it’s accessing a pair of properties on your threeStrings called
component1 and component2. If you actually go ahead and look at the implementation of
your list of type List<Int>, you might notice that neither component1 or component2 are defined as properties in the class.

What the creators of Kotlin did was actually implement 5 extension functions on many of the classes in the Collections.kt library that we commonly use.

operator fun <T> List<T>.component1(): T
operator fun <T> List<T>.component2(): T
operator fun <T> List<T>.component3(): T
operator fun <T> List<T>.component4(): T
operator fun <T> List<T>.component5(): T

Under the hood, Kotlin is actually calling the component function up until the fifth element
that you want to pull out of your collection. This is why in Example 2, you were getting this
error when trying to pull six elements out of your list. Kotlin: Destructuring declaration
initializer of type List<String> must have a 'component6()' function.
Kotlin did not
actually implement an extension function to pull out component6().

If you look at the explicit documentation for component1() with the only difference between itself, you can actually see that that it really is implemented on Kotlin Collections not just a List like in our example:

operator fun <T> Array<out T>.component1(): T
operator fun ByteArray.component1(): Byte
operator fun ShortArray.component1(): Short
operator fun IntArray.component1(): Int
operator fun LongArray.component1(): Long
operator fun FloatArray.component1(): Float
operator fun DoubleArray.component1(): Double
operator fun BooleanArray.component1(): Boolean
operator fun CharArray.component1(): Char
operator fun <T> List<T>.component1(): T

component2()component5() look the same as component1()

Destructuring Data classes

Like with collections, you can also destructure the properties in your data classes

data class Numbers(val first: String, 
                val second: String, 
                val third: String, 
                val fourth: String, 
                val fifth: String,
                val sixth: String)
                
val (one, two, three, four, five, six) = Numbers("one", "two", "three", "four", "five", "six")

With your data class, you can actually compile this code even though you are trying to pull
out 6 elements. Why then, were you given an error trying to do the same thing with a
collection? Destructuring data class works a little differently than destructuring
collections. When you look at what Kotlin is doing when this is compiled, you’ll notice
that it actually added a component for each property that was passed into the constructor
of your Numbers data class.

Data classes in Kotlin actually define a series of componentN functions at compile time,
where N is the amount of values you’re passing into the constructor. Because these aren’t
extension functions that are part of the Kotlin standard library, but functions that are
generated by Kotlin, if you were to decompile this data class you can actually see all the
generated componentN functions inside of the class.

public final int component1() {
    return this.first;
}

public final int component2() {
    return this.second;
}

public final int component3() {
    return this.third
}

Conclusion

You now know about what’s happening with componentN under the hood.
We’ve ruined the magic and shown that Kotlin is just doing work under the hood to allow us
to pull out the values that we want. If you have any questions, I’d love to hear from you.
Feel free to reach out at @rmorenocesar, or comment below!

The post Kotlin Destructuring Declarations and ComponentN appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/kotlin-destructuring-declarations-and-componentn/feed/ 0
Doing work with Android’s new WorkManager https://bignerdranch.com/blog/doing-work-with-androids-new-workmanager/ https://bignerdranch.com/blog/doing-work-with-androids-new-workmanager/#respond Sun, 20 May 2018 10:00:23 +0000 https://nerdranchighq.wpengine.com/blog/doing-work-with-androids-new-workmanager/ Google announced a really exciting feature at this year’s Google I/O that allows developers to perform background tasks that would traditionally require detailed knowledge of various API levels and the background task libraries available for those APIs. WorkManager offers up the functionality that you would get from other APIs such as JobScheduler, FirebaseJobDispatcher, AlarmManager and Services, without the overhead of having to research which one is available for your device or API.

The post Doing work with Android’s new WorkManager appeared first on Big Nerd Ranch.

]]>

Google announced a really exciting feature at this year’s Google I/O that allows
developers to perform background tasks that would traditionally require detailed
knowledge of various API levels and the background task libraries available for
those APIs. WorkManager
offers up the functionality that you would get from other APIs such as JobScheduler,
FirebaseJobDispatcher, AlarmManager and Services, without the overhead of having to research which
one is available for your device or API.

If you’ve been around the block, you’ve probably seen a few Android versions come and go
along with different ways to do work in the background. These APIs have always been hard
to keep up with as Google added new features and deprecated old ones. The documentation was unclear
about the right way of doing work on a background thread.

Consider trying to run a long running task using a JobScheduler that is scheduled to
start your Job. The system will start your JobService when the time comes, but the
minimum SDK that you can use with JobScheduler is buggy at 21 and is actually usable
starting at 23. You might be targeting devices from SDK 21, so you’d also need to use a JobDispatcher
for devices using your app at that API level. Since this JobScheduler might not be available to you
you could use the FirebaseJobDispatcher, but it requires play services which means that you’d
be leaving out a ton of non Google devices that run Android. Depending on what you’re doing, it might make sense
to use the AlarmManager but it’s not always the best choice. As possibly your final
solution you might use a regular IntentService, but according to the Google docs

Note: If your app targets API level 26 or higher, the system imposes restrictions on
running background services when the app itself isn’t in the foreground. In most cases like
this, your app should use a scheduled job instead.

So now we’re back to where we started. In the past, choosing the best background scheduler has been
hard, and this
is why the new WorkManager is so great. It chooses the appropriate way to run your task based on app state
and the API level.

WorkManager Components

  • WorkManager – receives the work with specific arguments and enqueues that work.

  • Worker – implements doWork() which executes the functionality on the background thread.

  • WorkRequest – represents an individual task. It will tell you which Worker is enqueued as well as what constraints
    it needs to meet in order for it to run. WorkRequest is an abstract class that you’ll be using with OneTimeWorkRequest
    or PeriodicWorkRequest.

  • WorkStatus – provides data for each WorkRequest object.

Let’s get hands on now with an example putting this all together.

Create your class extending Worker and implement the doWork() method.

class YourWorker: Worker {
  override fun WorkerResult doWork() {
    //do the work you want done on the background in here
     
    return WorkerResult.SUCCESS
  }
}

Having set up the work you want to get done, you would then call the WorkManager in order to queue up
the work you want to execute. You can specify constraints that will dictate under what conditions
the work will get done.

val work: OneTimeWorkRequest  = OneTimeWorkRequest.Builder(YourWorker::class.java).build()
WorkManager.getInstance().enqueue(work)

Because we are using a OneTimeWorkRequest and there were no constraints specified. The WorkManager runs the
task immediately.

If we wanted to, we could limit our WorkManager to run our request one time only if we have a network connection
and our device is currently charging.

val constraints: Constraints = Constraints.Builder()
   .setRequiredNetworkType(NetworkType.CONNECTED)
   .setRequiresCharging(true)
   .build()

And the way we set up our work request would only change to accept these constraints

val work: OneTimeWorkRequest = OneTimeWorkRequest.Builder(SomeWorker::class.java).setConstraints(constraints).build()

If you wanted the work to happen more than once, there is the previously mentioned PeriodicWorkRequest for that as
well. You can set it up in a very similar fashion, but you’d just specify a timer interval that you’d want the work to
run on.

val recurringWork: PeriodicWorkRequest = PeriodicWorkRequest.Builder(YourWorker::class.java, 3, TimeUnit.HOURS).build()
WorkManager.getInstance().enqueue(recurringWork)

The wonderful thing about this API is that you don’t have to write any device logic or worry about selecting
the best API for running these tasks. WorkManager has been doing all of that work for you!

But wait, there’s more!

If you wanted to run multiple tasks that are doing background thread work, we could chain together those tasks
by creating a sequence of OneTimeWorkRequests with our WorkManager

WorkManager.getInstance().beginWith(firstWork)
  .then(secondWork)
  .then(thirdWork)
  .enqueue()

If at any point one task fails, then the whole sequence will end.

This post just touches the surface on chaining these work requests. There are multiple ways to combine and run these
tasks in parallel that you should explore.

Google keeps us on our toes with their continuous improvements to the framework, and hopefully by now you’re giddy with
excitement to get started exploring the work you can do with Android’s new WorkManager.

The post Doing work with Android’s new WorkManager appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/doing-work-with-androids-new-workmanager/feed/ 0
Android Auto Backup and Your Developer Workflow https://bignerdranch.com/blog/android-auto-backup-and-your-developer-workflow/ https://bignerdranch.com/blog/android-auto-backup-and-your-developer-workflow/#respond Sun, 01 Apr 2018 10:00:23 +0000 https://nerdranchighq.wpengine.com/blog/android-auto-backup-and-your-developer-workflow/ Auto Backup is a nifty feature introduced in Android 6.0 (23) that allows users to have the data from their apps backed up onto their Google Drive accounts. You can leverage auto backup in your Android app so that your users can more quickly recover their data if they ever switch phones or reinstall your app after having uninstalled it.

The post Android Auto Backup and Your Developer Workflow appeared first on Big Nerd Ranch.

]]>

Auto Backup is a nifty feature introduced in Android 6.0 (23) that allows users to have the data from their apps backed up onto their Google Drive accounts.

You can leverage auto backup in your Android app so that your users can more quickly recover their data if they ever switch phones or reinstall your app after having uninstalled it.

Users can store up to 25MB of data which persists across the lifetime of an app being installed on your device.

If the user deletes the app in any way, including via a factory reset of their device, the data for the app will still be available when the user re-downloads the app and the .apk is installed. Auto Backup also works across devices, meaning that when your user gets a new phone, they won’t lose key information from your app.

This sounds like a pretty great feature for your users.
So what kinds of issues might you as a developer need to keep an eye out for?

This post will explore:

  • Where you can enable Auto Backup
  • Exactly what user data you can expect Auto Backup will save
  • Some caveats you must take into consideration as a developer that may influence your workflow
  • How you can control what data is actually stored

How to Enable Auto Backup

Users are first prompted to enable Auto Backup when setting up their phone for the first time.
If they need to do so after the fact, they can enable back ups of their data by navigating to Settings -> Backup & Reset, and opting in to having their data stored on their Google Drive.

Image of phone settings depicting where a user can go to enable autobackup for their phone

The device backs up all of the eligible data in the 24 hours since the last Auto Backup was completed, as long as your phone is charged, idle, and connected to a Wi-Fi network.
Unless those constraints are met, the backup will never happen.
This is because during the backup the system shuts down the apps that are getting backed up to make sure they are not writing anything else to the file system.
As such, apps in the foreground won’t actually be getting backed up.

As a developer you can support Auto Backup in your app by toggling it in your manifest.
If you are targeting any version 6.0 and up, it should already be enabled by default with the android:allowBackup="true" in the manifest’s <application> tag.

If you want to override the default behavior of having to shut down the app in order to back it up, you can also include the setting android:backupInForeground="true".

What Is Backed Up

As a developer, you probably store and cache a lot of data on your apps.
So what data am I talking about when I keep saying that your data gets stored in your drive by Auto Backup?

  • Shared preferences

  • Files in your app’s internal storage: getFilesDir() and getDir(String, Int).

  • Files stored in your databases: getDatabasePath(String).

These seem to encompass most of the data that persists in your application, but some notable sources of data that isn’t backed up are data that gets cached for your app by the Android OS and user permissions.

Namely, information in directories accessing via the following APIs:

  • getCacheDir()

  • getCodeCacheDir()

  • getNoBackupFilesDir()

Managing the Auto Backup User Experience

In getting to know a little bit about how Auto Backup works, you might be wondering if it’s an all-or-nothing game: Is a massive, uncontrollable chunk of data sent up by the system?

As it turns out, Android gives you a lot of flexibility on handling what is sent up to our Drives.

Specify What You Want to Include or Exclude from the Backup

As previously stated, Auto Backup backs up almost all of your data, but you can define an .xml file that allows us to specify rules for what you allow to get backed up.

You can do this in just a couple of steps.

  • Create an xml file auto_backup_rules.xml in the res/xml directory.

  • Specify what you want to include or exclude from the backup using the syntax below:

    • If a type is specified in both the include and the exclude tags, the item specified in the exclude tag takes precedence
    • You can add a new <include> or <exclude> tag for every new resource you want to specify
    • The path tag specifies the path to a resource you want to include or exclude. For example:
      • <exclude domain="database" path="my_db.db"/>
      <full-backup-content>  
          <include  domain=["file" | "database" | "sharedpref" | "external" | "root"] path="string" />  
          <exclude  domain=["file" | "database" | "sharedpref" | "external" | "root"] path="string" />  
      </full-backup-content>
    

  • Include your backup file in your Android Manifest:
      <application ... 
          android:fullBackupContent="@xml/my_backup_rules">
    

  • Below is an example where you might decide you actually want to include all of your Shared Preferences, except some user credentials.

      <?xml version="1.0" encoding="utf-8"?>
      <full-backup-content>
          <include domain="sharedpref" path="."/>
          <exclude domain="sharedpref" path="credentials.xml"/>
      </full-backup-content>
    

Disable Auto Backup Completely

If you choose to not support Auto Backup, replace android:allowAutoBackup="true" in your manifest with the following.

<application ...
	android:allowBackup="false"  
	tools:replace="android:allowBackup"

This will make sure that your app data never gets backed up by the system.

This also eliminates the possibility of potentially backing up any data that might be particularly sensitive.

Without a backup, however, you may have to rely on some other way to keep track of the state of your app on a new install, such as recovering data from a REST endpoint that you have access to.

After some time, you should no longer see your app when managing app backups on your Google Drive, because obsolete datasets are deleted after being inactive.

How Does Auto Backup Affect Your Developer Workflow?

As a developer, you probably run fresh builds from Android Studio on your devices and usually have an expectation of the state your app will be in.

If you uninstall the app from your device, you may expect that all the app data from the previous installation is deleted.
This isn’t true while you have Auto Backup enabled if you haven’t specified what should be backed up.

Consider this test case using Shared Preferences: Being a new user coming onto the app for the first time.

You may have an Activity that checks for first-time users by querying for the user information that’s been stored in a variety of ways.

In this case, you decided to store whether or not someone was a first time user in Shared Preferences.

if (!user.firstTime()) {
  //navigate to Home Activity
} else {
  //take user through onboarding process
}

Since, by default, Shared Preferences is backed up, if you had any Shared Preferences data stored during the last Auto Backup, when you uninstall your app and run your build to test the on-boarding flow, you will still always have the stored Shared Preference values.
In this case, that stored value says that this user is not a first time user.

That means that even though you’re running new builds, your app always thinks that an existing user is entering every time and you will never run your on-boarding flow.

Disable Auto Backup in Your Dev Flavor

If you decide that you want to support Auto Backup for your users but you don’t want the unforeseen circumstances it might cause in manual testing and debugging, you may choose to have different manifest files for each flavor that you have in your build.

Your main Android Manifest file would include Auto Backup, along with the rest of your project configuration, and your debug Android Manifest would only have the command that turns Auto Backup off.

Since your manifests are merged when your APK is packaged, this means you don’t have to have two complete versions of your manifest for both product flavors.

What Now?

You now hopefully know a little more about why your data, like the cat you keep feeding, keeps coming back, why it’s happening and how to control it.

Go forth and Auto Backup!

The post Android Auto Backup and Your Developer Workflow appeared first on Big Nerd Ranch.

]]>
https://bignerdranch.com/blog/android-auto-backup-and-your-developer-workflow/feed/ 0