loading...
Cover image for Matt's Tidbits #59 - Unexpected new lint failures

Matt's Tidbits #59 - Unexpected new lint failures

mpeng3 profile image Matthew Groves Originally published at Medium ・3 min read

Matt's Tidbits (42 Part Series)

1) Matt’s Tidbits #35 - A strategy for debugging complex unit test failures 2) Matt’s Tidbits #36 - How to get complete code coverage in unit tests for a nullable Kotlin “var” 3 ... 40 3) Matt's Tidbits #37 - How to run apps on multiple devices simultaneously! 4) Matt's Tidbits #38 - An elegant way of dealing with RxLifecycle lint warnings 5) Matt’s Tidbits #39 - Why writing tests is so important 6) Matt's Tidbits #40 - RxJava doOnSubscribe() behavior explained 7) Matt's Tidbits #41 - Converting a BehaviorRelay into a PublishRelay 8) Matt's Tidbits #42 - The answer to the Ultimate Question of Life, the Universe, and Everything… 9) Matt's Tidbits #43 - Making the most of your phone’s sensors 10) Matt's Tidbits #44 - How to take great screenshots on Android 11) Matt's Tidbits #45 - Creating a private token class 12) Matt's Tidbits #46 - Scratch files 13) Matt's Tidbits #47 - Finding list items by title in Espresso 14) Matt's Tidbits #48 - Separating out search results for test code 15) Matt's Tidbits #49 - What to do when your (Log)cat misbehaves 16) Matt's Tidbits #50 - How to (inadvertently) initialize a Kotlin val twice 17) Matt's Tidbits #51 - Easy stack traces 18) Matt's Tidbits #52 - Formatting etiquette 19) Matt's Tidbits #53 - First year in review 20) Matt's Tidbits #54 - Caches, deployments, and IT - oh my! 21) Matt's Tidbits #55 - Strange Breakpoint behavior with Rx schedulers 22) Matt's Tidbits #56 - Be careful with @JvmOverloads 23) Matt's Tidbits #57 - Improving RxJava stack traces 24) Matt's Tidbits #58 - A strange issue when upgrading to Android Studio 3.6 25) Matt's Tidbits #59 - Unexpected new lint failures 26) Matt's Tidbits #60 - Cleanly handling null values in Kotlin 27) Matt's Tidbits #61 - Getting out of a dependency cycle 28) Matt's Tidbits #62 - When you're feeling exhausted... 29) Matt's Tidbits #63 - Some good news about AGP 3.6.2 30) Matt's Tidbits #64 - Digging into some Ham...crest assertions 31) Matt's Tidbits #65 - It's time for proper support for JUnit 5 32) Matt's Tidbits #66 - The magic of Kotlin's "reified" keyword 33) Matt's Tidbits #67 - Some tips for working from home 34) Matt's Tidbits #68 - Testing RxJava Observables 35) Matt's Tidbits #69 - Neat Kotlin field tricks 36) Matt's Tidbits #70 - Cleaner diffs! 37) Matt's Tidbits #71 - Trying to figure out what to say 38) Matt's Tidbits #72 - Migrating from RxJava 2 -> 3 39) Matt's Tidbits #73 - Deciding which Kotlin scope function to use 40) Matt's Tidbits #74 - Resolving an interesting Kotlin <-> Java interop issue 41) Matt's Tidbits #75 - Moving tidbits! 42) Matt's Tidbits #76 - A long-overdue feature

Last week I wrote about an issue you might run into when upgrading the Android Gradle Plugin to 3.6. This time, I have a story about another issue related to that same upgrade.

After resolving the compilation issues from my last tidbit, everything seemed good to go — until we submitted a pull request and our continuous integration server reported some lint errors.

For some reason we were receiving the following error:

Error: TypedArrayUtils can only be called from within the same library group prefix (referenced groupId=androidx.core with prefix androidx from groupId=my-project) [RestrictedApi]

This seemed really odd — we hadn’t changed any code, only the version of the Android Gradle Plugin (and other code that was using WorkManager).

So, I downloaded the Android source code and went on a mission to try to figure out when this API had changed — thinking perhaps it had only recently been restricted. Unfortunately, that ended up being a bit of a wild goose chase — this code had been shuffled around a bunch during the migration to AndroidX, but it looked like that @RestrictTo annotation had been there for at least 2 years… So, that wasn’t it.

Instead, I checked out a version of my project right before the Android Gradle Plugin upgrade (using version 3.5.3), and went and looked at the source for TypedArrayUtils — the annotation was definitely still there. And, just to make sure I wasn’t imagining things, when I ran lint, no error was reported.

The only thing I’m able to conclude is that there must have been some kind of bug in lint that the latest version of the Android Gradle Plugin resolves. The release notes have the following note, which isn’t quite the same thing, but perhaps it’s related?

D8 now respects CLASS retention policy for annotations
When compiling your app, D8 now respects when annotations apply a CLASS retention policy, and those annotations are no longer available at runtime. This behavior also exists when setting the app’s target SDK to API level 23, which previously allowed access to these annotations during runtime when compiling your app using older versions of the Android Gradle plugin and D8.

Google is pretty clear that they hold the right to graylist/blacklist APIs with each new release of Android: https://developer.android.com/distribute/best-practices/develop/restrictions-non-sdk-interfaces

After consulting with the rest of my team, we all came to the conclusion that it was best to try to resolve the underlying issue (and stop using the restricted API), instead of simply ignoring the lint error.

The code that was using this restricted API looked like this:

public class MyListPreference extends ListPreference {
  public MyListPreference(Context context, AttributeSet attrs) {
    this(
      context,
      attrs,
      TypedArrayUtils.getAttr(
        context,
        androidx.preference.R.attr.dialogPreferenceStyle,
        android.R.attr.dialogPreferenceStyle
      )
    );
    setLayoutResource(R.layout.settings_layout);
    ...
  }
}

Looking at this more closely, I recognized a pattern I had seen before — from one of my previous Tidbits, in fact! (#56)

While not strictly a View class, this class also follows the typical Android pattern of having 4 constructors with increasing numbers of arguments.

The implementation of the 2-argument constructor for ListPreference looks like this:

public ListPreference(Context context, AttributeSet attrs) {
  this(
    context,
    attrs,
    TypedArrayUtils.getAttr(
      context,
      R.attr.dialogPreferenceStyle,
      android.R.attr.dialogPreferenceStyle
    )
  );
}

If it looks familiar, it’s because it’s exactly what our code was doing! Then I realized the solution — instead of calling our 4-argument constructor, we should be calling the 2-argument version of super() and allowing it to set the default style attribute for us.

Now we no longer rely on a restricted API, and our code is that much better for it! We will not be susceptible to problems if Android decides to change the default style for ListPreferences in the future.

And, this should serve as another reminder — you should really call the appropriate/corresponding constructors instead of supplying default arguments yourself to the 4-argument constructor.

Hopefully you learned something that will help you if you encounter a similar problem! And, please let me know if you encounter other issues after upgrading to the latest version of the Android Gradle Plugin — leave a comment below! And, please follow me on Medium if you’re interested in being notified of future tidbits.

Interested in joining the awesome team here at Intrepid? We’re hiring!

This tidbit was discovered on March 4, 2020.

Matt's Tidbits (42 Part Series)

1) Matt’s Tidbits #35 - A strategy for debugging complex unit test failures 2) Matt’s Tidbits #36 - How to get complete code coverage in unit tests for a nullable Kotlin “var” 3 ... 40 3) Matt's Tidbits #37 - How to run apps on multiple devices simultaneously! 4) Matt's Tidbits #38 - An elegant way of dealing with RxLifecycle lint warnings 5) Matt’s Tidbits #39 - Why writing tests is so important 6) Matt's Tidbits #40 - RxJava doOnSubscribe() behavior explained 7) Matt's Tidbits #41 - Converting a BehaviorRelay into a PublishRelay 8) Matt's Tidbits #42 - The answer to the Ultimate Question of Life, the Universe, and Everything… 9) Matt's Tidbits #43 - Making the most of your phone’s sensors 10) Matt's Tidbits #44 - How to take great screenshots on Android 11) Matt's Tidbits #45 - Creating a private token class 12) Matt's Tidbits #46 - Scratch files 13) Matt's Tidbits #47 - Finding list items by title in Espresso 14) Matt's Tidbits #48 - Separating out search results for test code 15) Matt's Tidbits #49 - What to do when your (Log)cat misbehaves 16) Matt's Tidbits #50 - How to (inadvertently) initialize a Kotlin val twice 17) Matt's Tidbits #51 - Easy stack traces 18) Matt's Tidbits #52 - Formatting etiquette 19) Matt's Tidbits #53 - First year in review 20) Matt's Tidbits #54 - Caches, deployments, and IT - oh my! 21) Matt's Tidbits #55 - Strange Breakpoint behavior with Rx schedulers 22) Matt's Tidbits #56 - Be careful with @JvmOverloads 23) Matt's Tidbits #57 - Improving RxJava stack traces 24) Matt's Tidbits #58 - A strange issue when upgrading to Android Studio 3.6 25) Matt's Tidbits #59 - Unexpected new lint failures 26) Matt's Tidbits #60 - Cleanly handling null values in Kotlin 27) Matt's Tidbits #61 - Getting out of a dependency cycle 28) Matt's Tidbits #62 - When you're feeling exhausted... 29) Matt's Tidbits #63 - Some good news about AGP 3.6.2 30) Matt's Tidbits #64 - Digging into some Ham...crest assertions 31) Matt's Tidbits #65 - It's time for proper support for JUnit 5 32) Matt's Tidbits #66 - The magic of Kotlin's "reified" keyword 33) Matt's Tidbits #67 - Some tips for working from home 34) Matt's Tidbits #68 - Testing RxJava Observables 35) Matt's Tidbits #69 - Neat Kotlin field tricks 36) Matt's Tidbits #70 - Cleaner diffs! 37) Matt's Tidbits #71 - Trying to figure out what to say 38) Matt's Tidbits #72 - Migrating from RxJava 2 -> 3 39) Matt's Tidbits #73 - Deciding which Kotlin scope function to use 40) Matt's Tidbits #74 - Resolving an interesting Kotlin <-> Java interop issue 41) Matt's Tidbits #75 - Moving tidbits! 42) Matt's Tidbits #76 - A long-overdue feature

Posted on by:

mpeng3 profile

Matthew Groves

@mpeng3

Software engineer with 10+ years of professional experience in C++, C#, Java, and Kotlin.

Discussion

markdown guide