Custom Espresso ViewAction

While working on a project for a client the design team had a pretty specific requirement for how EditText need to appear. I tried to bend TextInputEditText and TextInputLayout to my will but it just wasn't happening. This lead me to create a custom text input view which could show errors, hints, supporting labels, and suffixes in exactly the right way. I even ended up subclassing EditText to get some of these features.

Unfortunately this makes writing Espresso tests a little harder, leading to some very long and ugly onView(...) and failing replaceText(...) calls. By diving into ViewActions I was able to make a few modifications to smooth over this whole situation.

I started with ReplaceTextAction, copying the source into my own ReplaceTextInputViewAction since my class is called (TextInputView.) There are really on two important methods here - getConstraints() and perform()getConstraints() simply sets the requirements for the ViewAction to proceed, otherwise throwing an exception. perform() is where it actually does the action. This is where it can get exciting if you have a complicated custom view, but its important to have a nice clean interface to get/set the state of your View. Here is what I ended up with:

/**
 * Replaces view text by setting {@link TextInputView}s text property to given String.
 */
public final class ReplaceTextInputAction implements ViewAction {
    private final String stringToBeSet;

    public ReplaceTextInputAction(String value) {
        checkNotNull(value);
        this.stringToBeSet = value;
    }

    @SuppressWarnings("unchecked")
    @Override
    public Matcher getConstraints() {
        return allOf(isDisplayed(), isAssignableFrom(TextInputView.class));
    }

    @Override
    public void perform(UiController uiController, View view) {
        ((TextInputView) view).setText(stringToBeSet);
    }

    @Override
    public String getDescription() {
        return "replace text";
    }
}

I also created static helper methods to mimic what ViewActions is doing.

public class CustomViewActions {
    /**
     * Returns an action that updates the text attribute of a view.
     * View preconditions:
     * - must be displayed on screen
     * -must be assignable from TextInputView
     */
    public static ViewAction replaceTextInput(@Nonnull String stringToBeSet) {
        return actionWithAssertions(new ReplaceTextInputAction(stringToBeSet));
    }
}

This leads to not only a working test, but a nice and easy way to write tests for these custom Views.

onView(withId(R.id.email))
    .perform(replaceTextInput("foo@bar.com"));

Prevent spamming your crash reporter during development


Using a 3rd party crash reporter is one of the best things you can do to ensure a high quality app. If you don't know something's wrong how would you know it needs to be fixed? Non production builds can create a lot of noise making it difficult to separate real issues from normal development related crashes. You should draw a line between development, alpha, beta, and productions builds to focus your bug fixing efforts.

 

Conditionally turn it off

This works great if you have a simple set up consisting of development and production builds. You simply pass the BuildConfig.DEBUG flag, disabling the reporting at run time.

Crashlytics:

Fabric.with(this, Crashlytics.Builder()
                .core(CrashlyticsCore.Builder().disabled(BuildConfig.DEBUG).build())
                .build())

Instabug:

Instabug.Builder(this, "APP_TOKEN")
                .setCrashReportingState(if (BuildConfig.DEBUG)
                    InstabugFeature.State.DISABLED else InstabugFeature.State.ENABLED)
                .build()

Firebase:

FirebaseCrash.enableCrash(BuildConfig.DEBUG)
 

Segment builds with version numbers

This one is simple and keeps all of your crash data in one place. Simply change versionName in your build file to be something more descript. Maybe something like 1.2.3-alpha, 1.2.3-beta, etc. You now rely on the crash reporting dashboard to be able to cleanly segment and filter this data. One problem I see here is that it messes with aggregated statistics and it's harder for other people to jump in and extract data.

It's by far the simplest, covering the most cases with a single solution. It covers other things you might not think of either. Say for example you add BuildConfig.VERSION_NAME to your WebView or API user agent. You've now signaled to your backend you may be testing things out and those weird requests probably aren't anything to worry about.

// app/build.gradle
productFlavors {
    alpha {
        versionNameSuffix "-alpha"
    }
    beta {
        versionNameSuffix "-beta"
    }
}
 

Completely different buckets

Another options is to create entirely new apps or accounts for each variant of your app. I find this interesting because you get the best of all worlds, but it can be tricky to set up. This isn't my first choice, but for the right situation it's certainly a reasonable option.

Crashlytics:

// app/build.gradle
productFlavors {
    alpha {
        applicationIdSuffix ".alpha"
    }
    beta {
        applicationIdSuffix ".beta"
    }
}

Instabug:

// app/build.gradle
productFlavors {
    alpha {
        buildConfigField("String", "INSTABUG_TOKEN", "\"ALPHA_APP_TOKEN\"")
    }
    beta {
        buildConfigField("String", "INSTABUG_TOKEN", "\"BETA_APP_TOKEN\"")
    }
}
// Application#onCreate
Instabug.Builder(this, BuildConfig.INSTABUG_TOKEN).build()

Firebase:

You'll need to create multiple Firebase projects each with its own package name. From there you can generate a google-services.json for each.

// app/build.gradle
productFlavors {
    alpha {
        applicationIdSuffix ".alpha"
    }
    beta {
        applicationIdSuffix ".beta"
    }
}
// Add files in these directories
app/
    google-services.json
    src/alpha/google-services.json
    src/beta/google-services.json
    ...
 

So there you have it, multiple ways to group crash data with various crash reporting libraries. You'll no longer have to explain why there are 823 crashes from one user, every single day.

FragmentTransaction animation z-index trick

If you've ever worked with Fragments you will quickly learn they are can be tricky to animate. The basics can get you pretty far, but to set your app apart you'll need a little more than a simple cross fade or side-to-side slide. I won't be getting into shared element transitions, rather focusing on Fragments as unit for a screen in your app. I also acknowledge an entirely View based approach would be easier in some ways. How ever you found yourself trying to animate Fragments, here is a little tip to fix a z-indexing issue I recently encountered.

I was asked to implement a screen that slides up from the bottom, overlaying on top of the currently displayed one - simple, right? I created four animation XML resources with various <translate toYDelta=...> and rigged it up with setCustomAnimations(...) and this is what I got.

 
 

You can see here it's doing the right thing on the way out, but the way in was just wrong. This is in part due to support Fragment, where you are stuck with the old animation system. This means you have very little control over how things move in Z space and when the FragmentManager makes a bunch of assumptions around that detail, it can be problematic. I applied this fix in a BaseFragment which all of my other Fragment subclass.

override fun onCreateAnimation(transit: Int, enter: Boolean, nextAnim: Int): Animation? {
    if (nextAnim == R.anim.slide_enter) {
        val nextAnimation = AnimationUtils.loadAnimation(context, nextAnim)
        nextAnimation.setAnimationListener(object : Animation.AnimationListener {
            private var startZ = 0f
            override fun onAnimationStart(animation: Animation) {
                view?.apply {
                    startZ = ViewCompat.getTranslationZ(this)
                    ViewCompat.setTranslationZ(this, 1f)
                }
            }

            override fun onAnimationEnd(animation: Animation) {
                // Short delay required to prevent flicker since other Fragment wasn't removed just yet.
                view?.apply {
                    this.postDelayed({ ViewCompat.setTranslationZ(this, startZ) }, 100)
                }
            }

            override fun onAnimationRepeat(animation: Animation) {}
        })
        return nextAnimation
    } else {
        return null
    }
}

In a nutshell it raises the z-index of the Fragment's View only when it's performing an animation that requires the incoming screen to be on top during the animation. For example, the exit animation is perfect as is and we don't want to start swapping z-index there. Here is the final result, animating as expected.

 
 

Have you ever had weird Fragment animation issues?

Better smoothScrollToPosition()

A common UX pattern is to tap the top bar and scroll to the top. Easy enough, right? Not so fast. Take for example a RecyclerView with 200 items, scrolled down to position 82. In the first example smoothScrollToPosition makes you watch all these items fly by, increasing in duration the further you scrolled down - just imagine if you scrolled 1,000 items! betterSmoothScrollToPosition short circuits this leading to a consistent scroll every time.

 
smoothScrollToPosition
betterSmoothScrollToPosition
 

Here is a neat little Extension Function to handle this.

fun RecyclerView.betterSmoothScrollToPosition(targetItem: Int) {
    layoutManager?.apply {
        val maxScroll = 10
        when (this) {
            is LinearLayoutManager -> {
                val topItem = findFirstVisibleItemPosition()
                val distance = topItem - targetItem
                val anchorItem = when {
                    distance > maxScroll -> targetItem + maxScroll
                    distance < -maxScroll -> targetItem - maxScroll
                    else -> topItem
                }
                if (anchorItem != topItem) scrollToPosition(anchorItem)
                post {
                    smoothScrollToPosition(targetItem)
                }
            }
            else -> smoothScrollToPosition(targetItem)
        }
    }
}

In a nutshell, it immediately jumps to 10 rows away from the top, then it smooth scrolls. 10 is an arbitrary number but it keeps the example simple and works in many cases. You could always calculate a more appropriate number if you wanted to be more precise. Try it out and let me know what you think!

UI tools for Android development on Windows

Figma

Figma is the only app I've found to work with Sketch files on Windows. There are others, but they all fall short one way or the other. As a developer exporting assets yourself, you need control over layers, groups, and export settings. Figma nails all of them. I can't speak to it's merits as a design tool but I can tell you exporting raster or vector assets for Android apps works easily and exactly as expected.

Affinity Designer / Photo

On occasion I get already exported assets but sometimes they are the wrong size, have extra padding, or weren't exported optimally. In this case I reach for Affinity rather than deal with back and forth. Ever try to import an SVG and have Android Studio throw a bunch of warnings? Or maybe it looks great in Chrome, but messed up once converted to a Drawable XML resource? Open in Affinity Designer, then go to File > Export > SVG > Preset > SVG (for web). Tap Export and your SVG should be ready to go. It's cheaper than Adobe CS and covers both work and play quite well.

Instant Eye Dropper

Instant Eye Dropper does exactly what it says on the box - give you a quick way to capture a hex color code from pixels on your screen. Click and drag the system tray icon, then release over the pixel you want. The hex color is now in your clip board! This is useful for dealing with screenshots or other flat files you may come across.

BandiCam

If you ever find yourself needing to asynchronously share your screen, this is the app to do it. There are free options and very expensive ones, but BandiCam strikes the balance between features, ease of use, and price. It's also one of the few that can handle recording a 4k display at high frame rates and without steep compression or tearing.

Lightshot

Windows built in handling of "prt sc" is kind of lame. Lightshot gives you a quick and easy way to capture your entire screen or just a portion. You can annotate it right there, save it, or just copy to clip board.

So that's it, my top Windows tools for dealing with the more visual tasks I face while developing an Android app. Let me know what your favorites are.

gradle clean can't delete file on Windows

Every now and again I run into a problem where cleaning my Android build folder just doesn't work. You can use File Explorer, gradle, even WSL with a `sudo rm -rf app/build`, yet I am still unable to delete it. It's usually a single file that gets stuck. A reboot will certainly fix it, but there is a much simpler way!

  • Press Win+R and type resmon then click OK
  • Click the CPU tab and open Associated Handles
  • Type the stuck file's name into the search box
  • Look for adb.exe, java.exe, or some other Android related process
  • Right-click and select End Process

Now try deleting doing whatever Windows refused to do before. Coming from macOS and Linux I find this pretty silly. If you operate with admin privileges you should be able to completely own the file system, for better or worse. In this case, you are probably just trying to do your job and some tool got stuck.

Trying Microsoft Edge

 
 

I've been a die hard Chrome user for at least the last handful of years, but as I explore Windows 10 more I can't but help check out Edge. Right off the bat, it just feels right, much like Safari or GNOME Web do on their respective platforms. The security seems as good as Chrome, HTML5 support maybe a tad behind, but most of my extensions are there or have decent replacements.

LastPass and uBlock Origin are a must for password management and blocking pesky trackers. JSON Formatter for Edge makes viewing JSON in your browser way more doable. Saving content is also doable via Pocket, Evernote, Pinterest, and more. It's pretty amazing how far Microsoft's browser efforts have come since the days of IE. I love the little things like built in butter smooth PDF reader and find (match case and/or whole word.) There is a setting to use dark mode. All these things are fantastic, but there are some pretty annoying downsides.

  • Google Hangout video conferencing refuses to work. This is basically a deal breaker, but I have a work around.
  • The developer tools feel laggy and clunky.
  • "InPrivate" mode cannot be launched by default.
  • You cannot remove "Web Note" or "Share" from the tool bar. I don't use either and its annoying to have those extra buttons.

Most of those issues are just slightly annoying. However, Hangout's is a must for my day to day workflow. You can get around it by using a Chrome app and adding it to the Start Menu.

The end result will look something like this

The end result will look something like this

  1. Go to https://hangouts.google.com and click the "Video Call" button.
  2. Open the "..." Chrome menu and select "More > Add to desktop..."
  3. Check your desktop for the app shortcut.
  4. In File Explorer go to %appdata%\Microsoft\Windows\Start Menu
  5. Drag your newly created shortcut into this folder.

Any time I have a meeting I can quickly search for "hangouts" and immediately open an "app" for it while doing the rest of my work in Edge.

Kotlin as a first class language!

 
android_kotlin.png
 

This morning my wildest dreams came true - Kotlin became a first class language for Android development! This is exciting and it firms up what I've believed since the summer of 2015. Kotlin is the best language available to write native Android apps.

It's exciting because it means Google listens.

Pressure from developers has made it clear that Kotlin is where we see the platform going. It solves so many problems common to Android app development and brings features many developers lost hope of having. Method references, null data types, flexible control flows, lambdas, extension functions. There are plenty of libraries, hacks, and work arounds, but Kotlin brings consistency. The choice to support Kotlin means it will only get better and continue to flourish.

It's exciting because Kotlin can make you faster.

After the 1-2 days ramping up you find yourself accomplishing simple tasks in a fraction of the time it would have taken in Java. Language level features reduce ambiguity, drive readability, and make code more concise. You have first class nullability and you are forced to deal with it before you ship your app. It's as if JetBrains felt the pain of developing applications in Java and wrote a language to make it better (spoiler, they did.) You can see this throughout the language as you learn to write idiomatic Kotlin. You spend less time writing boilerplate (data classes anyone?) and more time writing interesting code.

It's exciting because it's rock solid on day one.

Years of testing and iteration before Google gave the green light has lead to a language and tool set that just works. It runs in your favorite IDE. It's works on every version of Android. Let me phrase this in another way - When was the last time you got an Android developer tool that just plain works. On day one. Like right now, go get it, and ship an app on the same day it was announced - 

This is the very first time and I hope this trend continues. Google doesn't need to invent everything and this proves that. They can be an amazing facilitator and still win. 

Clearly I am super jazzed about this and it's should be exciting for anyone who writes Android apps. You can check out my other Kotlin posts here and be sure to keep an eye out for more.

My back up strategy

While its not the most exciting topic, backing up your data is more important than you think. As more of our lives end up exclusively in digital formats they become more vulnerable to loss, theft, or damage. A good back up strategy is like an insurance policy. Its can be annoying to set up, maybe cost a little money, but in the event you need it, it can be a life saver.

3-2-1

The 3-2-1 rule is pretty simple. Three copies, two of which are local, one is in the cloud. Don't try to put those two local copies on the same drive either! Use two separate hard drives (or other physical media.)

Local copies

For hardware you can use any old external USB drives like my choice, the Western Digital My Passport Portable. I like portable drives because they are built to take a little rough handling so if you drop it, it should be more likely to survive than its desktop counter part. Speed isn't a concern and the built in encryption will prevent the novice snoop from having a look see.

For software I would suggest Acronis True Image on Windows or Carbon Copy Cloner on macOS. These cost a little money but offer great control over how and when your data is backed up. In addition they can backup system drives and offer a bootable backup so you have zero downtime in the case of a complete failure.

Windows File History and macOS FileVault  are your free options.

Cloud services

There are two options here. The simplest is something like Backblaze or Crash Plan. Both run silently in the background saving all your data to the cloud. Its great because you don't have to manage software or hardware. Download, pay a few bucks, and instantly gain peace of mind.

The second option is something like a Synology Disk Station or a Drobo. These put you in full control. You have to buy the hardware but there are no monthly fees. The other catch is you need to put this device somewhere other than your primary location. For example, leave it in a family members house or possibly at work (but get IT permission first!)

What do I use?

  • Western Digital My Passbook Portables (a bunch of them) + Acronis True Image + File History + Windows Backup
  • Synology Disk Station (2 disk model) connected over network
  • Backblaze on each computer

I have all drives backed up every 3 hours and retain version history where possible. I also stagger these, so cloud happens when local isn't and the local copies happen one at a time. This means if I mess up a document or have a hardware failure, its likely still around in one of my various back ups.

Android Bricks: Networking

When it comes to networking I've seen two major solutions, one of which is almost always wrong. The first is doing it all by hand, possibly using HTTPUrlConnection or maybe OkHttp. While the latter is the better choice, most apps should be using a proper networking library.

There are  bunch of reasons to do this. First, its battle tested and better handles edge cases. Its probably threaded nicely and allows for automatic parsing or mapping from a server response to local native objects. It also handles pressure better than something you'd whip up in an hour or two. Further someone else takes the burden or maintaining and you can fix buts, meaning we all benefit. So what are your options?

Volley

This is Google's thing. At first blush it looks great, seems official, very easy use and integrate. Its pretty basic Java with callbacks. "Here's a url, fetch me some data, I'd like it in JSON," and thats that. A pretty basic set up looks like this.

// add in build.gradle
compile 'com.android.volley:volley:1.0.0'
val request = JsonObjectRequest(Request.Method.GET, url, null, 
    object: Response.Listener() {
        override fun onResponse(response: JSONObject) {
            // success!
        }
    }, 
    object : Response.ErrorListener() {
        override fun onErrorResponse(error: VolleyError) {
            // failure :(
        }
    })

So as you can see, its not too scary and tucks away all the threading and parsing for you. You can even have OkHttp power it, as to benefit from its handling of poor connections, support for more modern protocols, sensible defaults, and amazing flexibility should you need to dig deeper.

Retrofit

Defined with annotations Retrofit reduces boiler plate and clearly defines your API. It brings with it a plethora of converters, going far beyond JSON.org and String parsers. You can easily use GSON, Jackson, ProtocolBuffers, and more, simply by adding a line of code and a dependency. In my experience its also very good with memory and receives meaningful updates in a timely fashion.

// add in build.gradle
compile 'com.squareup.retrofit2:retrofit:2.1.0'
compile "com.squareup.retrofit2:converter-gson:2.1.0"
// define api
interface GitHubService {
  @GET("users/{user}/repos")
  fun listRepos(@Path("user") user: String): Call<List<Repo>>
}

// set up in a data manager
val retrofit = Retrofit.Builder()
    .baseUrl("https://api.github.com")
    .addConverterFactory(GsonConverterFactory.create())
    .build()
val service = retrofit.create(GitHubService::class.java)

// actually fetch data
service.listRepos("octocat").enqueue(object: Callback<List<Repo>?> {
            override fun onResponse(call: Call<List<Repo>?>, response: Response<List<Repo>?>?) {
            // success!
            }

            override fun onFailure(call: Call<List<Repo>?>, t: Throwable?) {
            // failure :(
            }
        })

As you can see there is quite a bit more structure here and I think thats great. The relationship between an app should be structured. It should be clear and easy to understand yet powerful enough for the client to mutate requests and responses as needed to meet requirements.

Retrofit makes it easy to modify headers and deal with POST requests. Caching can be enabled fairly easily and it supports RxJava if thats something you're interest in. To be clear, much of this is provided by OkHttp but the proper integration between these two libraries works wonders.

Recommendation

Go with Retrofit and don't look back. In the rare case you'd decide to switch to something else it has such a clean API and easy to follow open source code that you'll be able to swap it out with ease. It has no discernible shortcomings and excels where Volley falls flat. With Volley I've experienced so much resistance to getting work done thats its not longer worth the effort maintaining on older projects. From leaks, to inflexible response processing. Retrofit just works and thats what you want when dealing with data.

Kotlin Bricks: Using Android Extensions instead of ButterKnife

Kotlin Android Extensions is an add-on package and plugin that make it effortless to find a specific View in your layout. Similar to ButterKnife you don't have to write findViewById all over the place. That really where the similarities end and where Android Extensions really make your code (and work life) better.

To get started you need to add these to your module's ("app" in many cases) build.gradle file.

apply plugin: 'kotlin-android-extensions'

Now in your Activity, Fragment, or View subclass you can start accessing the strongly typed views in just two lines.

// add an import
import kotlinx.android.synthetic.main.YOUR_XML_LAYOUT_NAME.view.*

// access the view
tv.text = "Hello World!"

Thats it! There is no injecting, binding, or resetting anything. There is no casting. It's strongly typed so if it compiles, you won't get some runtime exception complaining about casting or a null pointer from a missing view.

Kotlin Bricks: Extension functions to clean up Compat classes

You have to hand it to Google and the Android team for solving the difficult problem of OS distribution and the long tail of support we must provide as Android developers. One solution is classes like ViewCompat, TextUtilsCompat, and ActivityCompat.

These days it seems like there is a Compat version of every class. It often leads to some ugly and verbose syntax or worse, you end up using the same old deprecated version. Resources and ResourcesCompat bugs me every time and it really mucks up otherwise readable code. Here are a few snippets I use to hide away the mess.

fun Resources.color(@ColorRes color: Int, theme: Resources.Theme? = null): Int {
    return ResourcesCompat.getColor(this, color, theme)
}

fun Resources.colorStateList(@ColorRes color: Int, theme: Resources.Theme? = null): ColorStateList {
    return ResourcesCompat.getColorStateList(this, color, theme)!!
}

fun Resources.drawable(@DrawableRes drawable: Int, theme: Resources.Theme? = null): Drawable {
    return ResourcesCompat.getDrawable(this, drawable, theme)!!
}

Using extension functions we can make the plain old Resources from your Fragment or View use the Compat variant. The solution can not only provide a sensible default, but also allows you to customize the theme if you want to. When you go to use this, you'll see how much cleaner it is.

// from support library
ResourcesCompat.getColor(resources, R.color.red, null)

// much better with extention function
resources.color(R.color.red)

Kotlin Bricks: When is better than If

One of my favorite things about Kotlin is the when expression. Its like a combination of an if and a switch you might be familiar with from Java. Performance is that of a standard if statement, , but it reads better and is more functional. Here is a quick example that handles specific values, ranges, and anything beyond.

val people = 10
when (people) {
    0 -> print("none")
    1 -> print("party of one")
    2 -> print("a couple")
    3, 4, 5 -> print("a few")
    in 6..12 -> print("a group")
    in 13..50 -> print("a gathering")
    else -> print("way too many")
}

My favorite ways to use when is to have it return a value based on a condition. Here is an example where I get a string based on the value of an enum.

val message = when (status) {
    Status.ONLINE -> R.string.connected
    Status.OFFLINE -> R.string.offline
    Status.CHECKING -> R.string.checking
    else -> R.string.unknown
}

Another way to use when is more like an if else statement. I generally don't use there because it can lead to comprehension issues. Here is an example where a mammal weighing more than 300 it would never reach the print statement, even though you might expect it to.

when {
    animal.isMammal() -> growHair()
    animal.isBird() -> {
        fly()
        makeNest()
        layEgg()
    }
    animal.weight > 300 -> print("make way")
}

Kotlin Bricks: One strategy to avoid nullable types

If you use Fragments, imagine this common situation where you passed values in via the appropriate setArguments call. The arguments bundle contains a model that you'll reference all over the fragment code. Grabbing it from the bundle every time could be messy and wasteful, especially if it never null.

var model:Bundle? = null
override fun onCreate(si: Bundle?) {
    super.onCreate(si)
    model = arguments.getParcelable("model")
    model?.getString("foo")
}

That might be your first approach, however every time you access model you'll need to dereference it with ? or !!. Since I guaranteed at the top that our app will always pass "model" in the Fragment arguments, we can do something slightly differently to avoid all of that.

val model by lazy { arguments.getParcelable<Bundle>("model") }
override fun onCreate(si: Bundle?) {
    super.onCreate(si)
    model.getString("foo")
}

By using lazy delegates we can make the model property non-null and use the Fragment arguments. This technique is useful in Android subclasses where you don't have much control over the lifecycle, but still want control over the nullability of your properties.

lazy works by waiting until the first time you access a property to actually assign it. This usually works well but you have to be cautious when you first call it. For example, calling the in constructor would cause a NullPointerException because arguments was not set yet.

Kotlin Bricks: Avoid lots of safe dereference using apply

Coming from a Java background its very common to null check quite a bit to avoid the billon dollar mistake. Kotlin solves this by introducing a null variant to every type so when you get the dreaded NullPointerException its probably a serious issue you should deal with. When starting out with Kotlin your instinct says drop ? everywhere, you know, just to be safe.

Consider this example where we did a good job to guard against a crash should onNetworkSuccess return after our UI has been destroyed. While simple, there are still three textView? and you could imagine it growing pretty quickly as you make a more complex UI.

var textView: TextView? = null

override fun onCreate(si: Bundle?) {
    super.onCreate(si)
    textView = findViewById(R.id.tv) as TextView?
}

fun onNetworkSuccess(message: String) {
    if (message.isNotEmpty()) {
        textView?.text = message
        textView?.visibility = VISIBLE
    } else {
        textView?.visibility = GONE
    }
}

As an alternative we can use the apply function to not only use the safe operator once but also avoid any unnecessary work if the view ends up being null. I think the code also read better this way.

fun onNetworkSuccess(message: String) {
    textView?.apply {
        if (message.isNotEmpty()) {
            text = message
            visibility = VISIBLE
        } else {
            visibility = GONE
        }       
    }
}

<activity-alias>

Unless you've been bit by it before or came across Dan Lew's post, you may have never heard of <activity-alias>. Residing in your AndroidManifest.xml and around since API 1 it represents an alias or symlink to a concrete Activity. One of the best use cases is to prevent launcher icon shortcuts being removed when you change your activities android:name. This is because that identifier is both a file and an externally exposed identifier. When a launcher shortcut is created its linking exactly to that Activity.

Should you refactor that file's name or location you'll break the link. Most commonly the icon just disappears from the users home screen, but is still visible in the All Apps drawer. In other cases the icon remains, but the device says the app is not installed. At best its a minor inconvenience but if you have detailed analytics you might find it negatively impacts usage metrics. Many users just blame it on their phone, but in reality its just one of those hidden side effects of having parts of your app exposed as a public API.

Here is how to fix it:

<activity android:name=".activities.MainActivity" />
<activity-alias
  android:name=".MainActivity"
  android:targetActivity=".activities.MainActivity" >
    <intent-filter>
      <action android:name="android.intent.action.MAIN" />
      <category android:name="android.intent.category.LAUNCHER" />
    </intent-filter>
</activity-alias>

Of course there are a few gotchas that prevent this solution from being rock solid out of the box. Given all the various launchers, both 3rd party and shipped on device, you need to adhere to the following:

  1. <activity> must be declared before the <activity-alias> that intends to use it.
  2. android:name and android:targetActivity cannot be the same.

Once you've done this you'll be happy to know that Android Studio refactoring prevents you from messing up this configuration.

Android Studio vs. IntelliJ IDEA

Many Android new comers haven't experience the pain of Eclipse for Android development. When I started in 2009 it was the IDE and tool kit to use. IDEA from Jetbrains was around and had basic support for Android projects but it wasn't super compelling. In 2010 I made the switch and its been wonderful ever since. However it wasn't until Google I/O 2013 when they released the first version of Android Studio and even then it was a very subtle "we are probably going this direction but still love Eclipse" kind of move.

So beyond the mini history lesson, why does this matter? Because you can still use IntelliJ IDEA Community or Ultimate editions to build your Android apps and there are a couple of good reasons why I do this.

I find it more stable and up to date

Its true Android Studio is built using the open source Community edition, however, its often out of date. It took 6 months for Android Studio to upgrade from IDEA 15 to IDEA 16, which had some fantastic improvements

It does a lot more than just Android

If you find yourself working in multiple languages and frameworks IDEA Ultimate covers you more than Android Studio. I also find it way easier to create simple Java projects using IDEA, which is useful for sketching ideas or building pure Java or Kotlin libraries. If you are building a hybrid app, the web technology support is superior out of the box.

It can be configured without all the bloat

In my workflow I don't use many (if any) Google plugins. In Android Studio I choose to disable 10+ of them removing UI clutter and overhead. On the flip side, IDEA asks you up front what you do day to day to help customize your environment right from the start.

Worst case, its a great back up

If something just isn't right with your Android Studio, try IDEA. It could help sanity check if the issue is truly with your app, computer, or just Android Studio itself.

While IDEA Ultimate is my daily driver, I do still have Android Studio around. Many of the new utilities haven't made it into IDEA and in the off chance I need them its just a double click away.

What is Gradle?

While some of you may know Gradle (or Maven or Ant) from other projects, for Android developers its of great importance to understand and utilize Gradle to its fullest. Gradle ensures your builds run as consistently as possible across multiple devices while empowering you to dynamically change and easily update the core requirements of your application.

Its like a recipe

Take a standard recipe, like this awesome chocolate cake – it contains a description of all the parts and instructions required to make it. For starters, you need flour, sugar, oil, and a bunch of other things. These are the Gradle dependencies. You also need a bunch of tools like a bowl, mixer, and measuring instruments. These are the Gradle plugins. Where do you get all this stuff? Probably your pantry or the grocery store; these are Gradle (Maven) repositories.

Now that you've collected all of your tools and ingredients, you'll need to follow the instructions to actually make the cake. For Android developers this means configuring the android object, telling it how you want the app built. configurationsbuildscript, and many others also provide instructions.

Finally, you've completed the instructions for sifting, whisking, and folding. Now its time to bake this cake! In our analogy gradle or gradlew executable is the oven. You pass in your build.gradle file and it bakes you an APK.

While many stop here, often recipes leave room for interpretation to make it your own. This is where Gradle really shines. You can inject your own ingredients (dependencies), tools (plugins), and instructions (additional code.) Just like modifying a cake, this could change the entire process. Maybe it takes longer to bake (slower build times) or it outputs multiple cakes (like a magical cake copy machine.)

This is just the beginning

After you build a project or two you'll find that many open source projects and tools utilize Gradle. It could be generating more code, archiving artifacts, counting the methods in your app, running adb commands, or even sending a message to your group chat when its done.

Android Bricks: Image loading

There are three major image loading libraries on Android. Their purpose is to manage network requests, caching, and display of images loaded from your web server. This is a key component in many apps and I'll walk your through how to pick one.

Picasso & Glide

I lumped these first two together because they function very similarly internally. Based entirely in the standard Android heap, these represent a straight forward and simple solution to image loading. You access a singleton, with a url and target, then the library does the rest. Its a short and sweet single line with no other required set up.

Picasso

Picasso.with(ctx).load("https://placekitten.com/g/720/480").into(iv)

Glide

Glide.with(ctx).load("https://placekitten.com/g/720/480").into(iv)

As you can see they are nearly identical. The difference is that Glide is configured for better memory performance right out of the box. It decodes images as Bitmap.Config.RGB_565 and resizes them to fit the view they'll occupy. Together these two configurations lead to fewer memory spikes and lower sustained memory usage.

Its worth noting that Picasso can be configured to work near identically, but its not the default. At the time of this writing Picasso 2.5.2 is 18 months old and contains some unfixed edge case bugs you'll need to manually patch. Glide remains in active development and maintains more regular releases.

Fresco

Fresco is a product of Facebook's engineering team and backed by ashmem, making it a significantly different approach to nearly all other open source solutions. It is in heavy development but used on a massive scale. It also displays animated GIFs and progressive JPEGs giving it a leg up if you need support for either.

The biggest down side is the implementation. If you are dealing with a legacy codebase that loads a ton of images or has specialized needs you'll be hard pressed to adopt Fresco in a week, let alone a day. Since its such a different pattern and has its own special rules, you'll want to be 100% sure you like it before making a call one way or the other.

// In your custom Application.java
Fresco.initialize(ctx)

// Load image
draweeView.setImageURI(Uri.parse("https://placekitten.com/g/720/480"))

As you might have noticed, draweeView looks a little odd and it requires an initialization call. With Fresco you cannot use a standard ImageView due to its optimizations around memory usage. One last down side here is that if you have a custom ImageView that applies an effect, Fresco could make it way more complicated and you'll be stuck trying to make it work rather than using something off the self.

Recommendation

  1. If you load a low to moderate amount of images Glide is a great choice with complexity built in if you need it down the road. 
  2. If you need GIFs, progressive JPEGs, really care about memory, or push a ton of images through your app go, with Fresco
  3. If you are totally into Square engineering (and who isn't?) go with Picasso.

Faster Android builds

The bigger your app and team get, the slower your build will inevitably become. Here are a few tips to get you building faster. This guide is geared towards anyone responsible for buying machines for Android developers and focuses on rapid iteration.

Raw power

This is your profession, invest in decent tools. While its true that some famous musicians still play cheap guitars, this really doesn't translate to technology. Aim for these specs.

  1. In a desktop, shoot for as many processing cores as you can afford. 6-8 hyper threaded cores beats 4 cores at a higher clock speed. This means an i7 or Xeon desktop like the Dell Precision 7000 or the MacPro.
  2. In a laptop, portability is nice, but often leads to low power processors. i7 is required and avoid anything ending in U, like the i7-5557U found in 13" Macbook Pro. The Dell XPS i7 15" or the 15" Macbook Pro will keep you building fast on the go.
  3. 16Gb RAM minimum. Everything Android related is a memory hog and gets faster the more memory you can give it.
  4. SSD is required. The faster you get files from one place to another, the faster you build and deploy.

Project

Setting up your project correctly can really make a difference.

  1. Break your app into modules. This means properly decoupling chunks of your app into several standalone pieces. These can be built in parallel and even cached. Should your work be isolated to a single module, this will certainly speed things up.
  2. Carefully consider Gradle plugins and annotation processors. These could be slowing down builds because they are figuring stuff out when you build. Obvious but often overlooked.
  3. Configure your build.gradle to exclude things you don't need during rapid development. This cut off between 10%-30% build time in my experience.
  4. Avoid MultiDex if possible.

Gradle configuration

Gradle can be a blessing or a curse and you need to configure it to work optimally. After applying these settings my medium sized project build times went from 37s to 20s (clean assembleDebug)!

To get started, locate your gradle.properties file:

  • Linux: /home/<username>/.gradle/
  • Mac: /Users/<username>/.gradle/
  • Windows: C:\Users\<username>\.gradle

Next add the following lines to gradle.properties:

org.gradle.daemon=true
org.gradle.jvmargs=-Xms256m -Xmx3072m
org.gradle.parallel=true
kotlin.incremental=true

Lastly edit your build.gradle. Below is a starting point and according to the docs, there is a formula to adhere to. From experience you need to try out different settings to ensure you aren't negatively impacting your build times.

android {
  dexOptions {
    maxProcessCount 4
    javaMaxHeapSize "2g"
  }
}