Resource ID conflicts in an Android library project

Source: Internet
Author: User

1. Preface

One of the most useful features of Android Studio for modular development is the ability to create a new library project (module) under the main project, but there is a problem with the library project when it comes to resource ID collisions, because the SDK automatically helps us with the problem at compile time, so we don't usually notice But in some cases, we need to be aware of the existence of this problem.

For example, use the following code in a new library project:

public void OnButtonClick (view view) {    switch (View.getid ()) {case        r.id.button_1: Break            ;        Case r.id.button_2;            break;    }}

The IDE prompts you:

Resource IDs cannot is used in a switch statement in Android library modules less.

Validates using resource IDs in a switch statement in Android Library module. Resource IDs is non final in the library projects since SDK tools R14, means that the library code cannot treat these IDs As constants.

For example, we use Butterknife in the Library project in the following way, the compile time will be error.

@OnClick (r.id.button_1) public void OnButtonClick (view view) {}
2. Analysis

Either the switch statement or the annotation, there is a requirement that the value used must be a constant. In the main project, member variables in the R class are static and final decorated, and only static adornments are in the library project.

The R class generated in the Library project: Public final class R {public    static final class ID {public        static int button_1 = 0x7f0c0001;    } }//R class generated in main project: Public final class R {public    static final class ID {public        static final int text_1 = 2131165184;
   }}

Why is the resource ID generated in the library project not being final decorated? The official explanations are as follows:

Non-constant Labels

When multiple library projects are merged, the resource IDs in different projects may be duplicated. Prior to ADT 14, resource ID unification was defined as a static variable of the final type, whether it be a master project or a library project. As a result of this, the main project compiles when the resource ID conflict is found, the corresponding resource files in the library project and the code referencing the resource files need to be recompiled.

If the code uses a variable with the static final modifier, the variable is actually a constant, which is replaced with its value directly at compile time. At compile time, if the resource ID of the library project and the master project is duplicated, the resource is assigned a new ID and the code that was compiled before the library project is invalidated.

So what does it do when the variables in the Library project R class are only modified by static , and we can look at the compiled bytecode and then decompile it.

Activity:public class Mainactivity extends Appcompatactivity {    protected void onCreate (Bundle) in the main project Savedinstancestate) {        super.oncreate (savedinstancestate);        Source code: Setcontentview (r.layout.activity_main);        This.setcontentview (2131296283);    }} Activity:public Libactivity extends Appcompatactivity {    protected void onCreate (Bundle savedinstancestate) in library projects {        super.oncreate (savedinstancestate);        This.setcontentview (R.layout.activity_lib);    }}

The resource ID in the main project R class is static final decorated, and the compile time is replaced with the corresponding constant. The resource ID in the Library project R class is only static decorated, so the variable is preserved. This way, when the resource ID is sent a conflict, the main project R class is unchanged, the variables in the R class of the library project are modified, and the code that the Library project has compiled is still valid.

3, Butterknife in the R2 class

Since the resource ID in the library project cannot be defined as a constant, how do I use Butterknife in the Cuven project, the author provides the R2 class for me to use.

@OnClick ({R2.id.button_1, R2.id.button_2}) public void OnButtonClick (view view) {    int id = view.getid ();    if (id = = r.id.button_1) {        //...    } else if (id = = r.id.button_2) {        //...    }}

Yes, you use the R2 class in annotations, but you still need to use the R class in your code, because the ID in the R class is not constant, so you can only use the if statement to judge.

Let's take a look at the difference between the R2 class that butterknife generates for us and the R class:

R Class in library project: Public final class R {public    static final class ID {public        static int button_1 = 0x7f0c0001;    }} The R2 class Butterknife generated for us in the Library project: Public final class R2 {public    static final class ID {public        static final int Butto n_1 = 0x7f0c0001;    }}

Butterknife's job is simply to move the variables in the R class into the R2 class, and then add the final to all the variables. According to the foregoing, when the project is compiled as a whole, once the resource ID of the library project conflicts with the resource ID of the main project, the resource of the Library project is reassigned with the ID causing its R class to be modified. Obviously this process does not involve the R2 class, and the R2 class retains the obsolete ID. But what the Butterknife provides is not intended to provide run-time information, but to generate code at compile time.

public class Libactivity_viewbinding implements Unbinder {    private libactivity target;    Private View view_button_1;    Private View view_button_2;    @UiThread Public    libactivity_viewbinding (final libactivity target, View source) {        this.target = target;        View view = Utils.findrequiredview (source, R.id.button_1, "Method ' OnButtonClick '");        this.view_button_1 = view;        View.setonclicklistener ....        View = Utils.findrequiredview (source, R.id.button_2, "Method ' OnButtonClick '");        this.view_button_2 = view;        View.setonclicklistener...    }}

In the code generated by Butterknife, the R class is still used. R2 serves only to provide a symbolic name, as long as the program knows which variable to match when generating the code. This method can be said to be very "tricky".

Resource ID conflicts in an Android library project

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.