Skip to content
This repository was archived by the owner on Feb 26, 2023. It is now read-only.
This repository was archived by the owner on Feb 26, 2023. It is now read-only.

Use ContextCompat to retrieve drawables #1422

Description

@ened

Given I'm injecting a drawable into my fragment like that:

@DrawableRes(R.drawable.bg_button_with_stroke_orange)
protected Drawable backgroundDrawable;

Then Android Annotations generates this code:

private void init_() {
    Resources resources_ = context_.getResources();
    backgroundDrawable = resources_.getDrawable(drawable.bg_button_with_stroke_orange);
}

Which then generates this compiler warning for targetSdk=22 builds:

TheClass_.java:33: warning: [deprecation] getDrawable(int) in Resources has been deprecated
        backgroundDrawable = resources_.getDrawable(drawable.bg_button_with_stroke_orange);

Instead, AndroidAnnoations should, given the class ContextCompat is available, generate this:

private void init_() {
    backgroundDrawable = ContextCompat.getDrawable(context_, drawable.bg_button_with_stroke_orange);
}

Benefits:

  • Obviously, the compiler warning would be gone
  • More importantly, the theme will be applied to the drawable on Lollipop+ devices

Activity

  1. WonderCsabo commented on May 20, 2015

    @WonderCsabo
    Member

    Seems reasonable. Wanna contribute?

  2. ened commented on May 20, 2015

    @ened
    ContributorAuthor

    Would love to take care of it. Just no time right now. Keep it here for tracking, first.

  3. ened commented on May 20, 2015

    @ened
    ContributorAuthor

    Having that said, @WonderCsabo how could one actually check if the class is available? We'd have to add the "compile" scope into the annotation processing scope (apt) and check there. Is that even possible?

  4. WonderCsabo commented on May 20, 2015

    @WonderCsabo
    Member

    We can just check whether it is on the classpath and that is working already. We do not know anything about whether it will be really packaged into the app or not, but we expect it will be. We already do this kind of check when we generate the Activity builders.

  5. WonderCsabo commented on May 23, 2015

    @WonderCsabo
    Member

    @ened i forgot that we should handle the cases when ContextCompat is not available.

    minSdkVersion => 21 && ContextCompat is not available:

    backgroundDrawable = context.getDrawable();

    minSdkVersion < 21 && compileSdkVersion >=21 && ContextCompat is not available:

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
      backgroundDrawable = context.getDrawable();
    } else {
      backgroundDrawable = resources_.getDrawable();
    }

    Can you implement that?

  6. ened commented on May 24, 2015

    @ened
    ContributorAuthor

    Would that check be done during compile time or in a runtime switch? Probably generate the code like you showed it, right?

  7. WonderCsabo commented on May 24, 2015

    @WonderCsabo
    Member

    Yeah generate that code, the compile time conditional is in italic.

  8. ened commented on May 24, 2015

    @ened
    ContributorAuthor

    Ok cool. Is there another component that's doing such a check?

  9. WonderCsabo commented on May 24, 2015

    @WonderCsabo
    Member
  10. ened commented on May 24, 2015

    @ened
    ContributorAuthor

    Now I got something like this:

    private void init_(Bundle savedInstanceState) {
        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {
            myDrawable = this.getDrawable(drawable.myDrawable);
        } else {
            myDrawable = resources_.getDrawable(drawable.myDrawable);
        }
        Resources resources_ = this.getResources();
    }
    

    But I can't find out why the resources_ variable is initialized AFTER the usage. :)

    Heres the code that generates it:

    } else if (element.getAnnotation(DrawableRes.class) != null && !hasContextWithGetDrawableMethod() && hasGetDrawableInContext() && !hasContextCompatInClasspath()) {
        createCallWithIfGuard(holder, ref(fieldName), methodBody, idRef);
    
    private void createCallWithIfGuard(EComponentHolder holder, JFieldRef ref, JBlock methodBody, JFieldRef idRef) {
        JConditional guardIf = methodBody._if(holder.classes().BUILD_VERSION.staticRef("SDK_INT").gte(holder.classes().BUILD_VERSION_CODES.staticRef("LOLLIPOP")));
        JBlock ifBlock = guardIf._then();
        ifBlock.assign(ref, holder.getContextRef().invoke("getDrawable").arg(idRef));
    
        JBlock elseBlock = guardIf._else();
        elseBlock.assign(ref, holder.getResourcesRef().invoke("getDrawable").arg(idRef));
    }
    

    @WonderCsabo Spontaneous idea?

  11. ened commented on May 24, 2015

    @ened
    ContributorAuthor

    OK I found it. Just had to get a hold of the resourcesRef earlier. PR coming. :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions