9

I have 2 flavors - paidapp and freeapp. The only difference that paidapp have 1 more button on MainActivity, say "paidbutton". paidapp has its own layout with button android:id="@+id/paidbutton" and layout for freeapp does not have this button.

In code I use this:

if (BuildConfig.FLAVOR.equals("paidapp")) {
            View paidbutton = findViewById(R.id.paidbutton);
            paidbutton.setOnClickListener(new OnClickListener() {
                @Override
                public void onClick(View v) {
                    //...
                }
            });
}

But I have an error cannot find symbol variable in findViewById(R.id.paidbutton);

How to solve this problem without cloning MainActivity.java in both flavors?

EDIT1 - add more code examples:

Gradle:

productFlavors {
    paidapp {
    }
    freeapp {
    }
}

/app/src/main/res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/goNext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Go next" />

</LinearLayout>

/app/src/paidapp/res/layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <Button
        android:id="@+id/goNext"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Go next" />

    <Button
        android:id="@+id/paidbutton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="See more" />


</LinearLayout>

/app/src/main/java/company/com/myapplication/MainActivity.java

package company.com.myapplication;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;


public class MainActivity extends Activity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        View goNext = findViewById(R.id.goNext);
        goNext.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Toast.makeText(MainActivity.this, "goNext click", Toast.LENGTH_SHORT).show();
            }
        });

        if (BuildConfig.FLAVOR.equals("paidapp")) {
            View paidbutton = findViewById(R.id.paidbutton);
            paidbutton.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(MainActivity.this, "paidapp click", Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

}

EDIT2 - I have found some workaround using reflection, but still looking for normal solution:

instead of View paidbutton = findViewById(R.id.paidbutton); I have used View paidbutton = findViewById(getIdFromRId("paidbutton"));

where getIdFromRId is:

private int getIdFromRId(String idName) {
    int id = 0;
    try {
        Class c = R.id.class;
        Field field = c.getField(idName);
        id = field.getInt(null);
    } catch (Exception e) {
        // do nothing
    }
    return id;
}
anber
  • 2,914
  • 5
  • 32
  • 56
  • Facing same error but this seems expected behavior because when we switch to a particular `build variant(flavor)`, that flavor specific resources are loaded up hence the IDE gives error can't find symbol. You have **two options** 1. either you put both buttons in activity_main and use one layout file from main (no need for flavor specific version) and hide/show buttons on base of flavors at run time. 2. copy your `MainActivity.java` inside both flavors! – Muhammad Babar Mar 11 '16 at 10:23

3 Answers3

23

If you don't have paidbutton layout element at all in the freeapp product flavor, you can just declare corresponding id item in one of your resource xml files in freeapp product flavor folder. For example create the file src/freeapp/res/values/ids.xml containing:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <item name="paidbutton" type="id"/>
</resources>

After doing that you'll have no problems with compiling common code since the symbol R.id.paidbutton will be defined for both product flavors. findViewById() call will return the real layout element in paidapp build and will return null in freeapp build.

Alex Kravchenko
  • 841
  • 9
  • 11
1

Can you put your paidbutton XML tag and your MainActivity.java class imports please.

You are maybe using the wrong resource import like import android.R; instead of import my_package.R;

  • I do not have import R in imports – anber Dec 05 '14 at 10:10
  • Where your function is in the code? Before or after the setContentView() method? Compilator cannot find the R symbol because you are trying to use it before his initialization. – Alexis Burgos Dec 05 '14 at 14:26
  • Compilator can find R, but in R file there are no R.id.paidbutton for freeapp flavor and exist R.id.paidbutton for paidapp flavor. Thats why paidapp flavor assambled successfully but freeapp flavor not successfully. – anber Dec 05 '14 at 14:32
  • Well, on your Java exemple, you are not using your proper R claas. Add this import : "import company.com.myapplication.R" – Alexis Burgos Dec 06 '14 at 10:25
  • R file located in the same package as my MainActivity, so I do not need to import it. In any case, your advice does not help. – anber Dec 06 '14 at 13:00
  • I'm sorry, but I seems to me that you do not really understand the problem. I have 2 R files simultaneously with package company.com.myapplication.R, in one file I have R.id.paidbutton and in another - don't have. When I use import company.com.myapplication.R it will import both files simultaneously. – anber Dec 06 '14 at 13:04
  • I think you'll be force to clone your code (like 2 library). See that page: [link](http://tools.android.com/tech-docs/new-build-system/build-system-concepts) – Alexis Burgos Dec 06 '14 at 17:59
1

You need your if clause in the on create and then add the setContentView, so somethin like this:

if (BuildConfig.FLAVOR.equals("paidapp")) {
        setContentView(R.layout.activity_main_paid);
        View paidbutton = findViewById(R.id.paidbutton);
        paidbutton.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                //...
            }
        });
}
else{
    setContentView(R.layout.activity_main_free);
}

or you could possibly use one layout for both and just make the button invisible

I hope this helps

glm9637
  • 874
  • 8
  • 18
  • Why do i need activity_main_paid and activity_main_paid? I have just activity_main in both flavors – anber Dec 05 '14 at 10:08
  • these are just the different layouts, you only use one mainactivity, and in there you decide which layout you want to use – glm9637 Dec 05 '14 at 11:08
  • Looks like it will work, but it kill flavors idea with different sourceSets, I should care about which xml will be chousen manually instead of androidPlugin – anber Dec 05 '14 at 11:15