Android flavor - 在R文件中找不到符号变量

9

我有两个版本 - 付费应用和免费应用。 唯一的区别是付费应用在MainActivity上有一个额外的按钮,称为"paidbutton"。 付费应用有自己的布局,其中包含按钮android:id="@+id/paidbutton",而免费应用的布局没有此按钮。

在代码中,我使用以下内容:

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

但是我在findViewById(R.id.paidbutton);中遇到了错误cannot find symbol variable.

如何解决这个问题,而不需要在两个版本中克隆MainActivity.java文件?

编辑1 - 添加更多的代码示例:

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();
                }
            });
        }
    }

}

编辑2 - 我已经找到了一些使用反射的解决方法,但仍在寻找正常的解决方案:

不使用 View paidbutton = findViewById(R.id.paidbutton);,而是使用 View paidbutton = findViewById(getIdFromRId("paidbutton"));

其中getIdFromRId为:

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;
}

面对相同的错误,但这似乎是预期的行为,因为当我们切换到特定的“构建变体(flavor)”时,该变体特定的资源被加载,因此IDE会给出错误提示找不到符号。你有两个选项:1.将两个按钮都放在activity_main中,并在运行时根据flavors隐藏/显示按钮,使用一个来自main的布局文件(无需特定于flavor的版本)。2.将你的MainActivity.java复制到两个flavors中! - Muhammad Babar
3个回答

24

如果在freeapp产品风味中根本没有paidbutton布局元素,您可以在其中一个资源XML文件中声明相应的ID项。例如,创建文件src/freeapp/res/values/ids.xml并包含以下内容:

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

这样做后,由于R.id.paidbutton符号将为两个产品风格定义,因此编译常见代码时将不会出现任何问题。在paidapp构建中,findViewById()调用将返回实际的布局元素,并在freeapp构建中返回null。


1
你需要在onCreate方法中添加if语句,然后再添加setContentView方法,类似于这样:

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);
}

或者你可以使用同一个布局,只需将按钮隐藏即可。
我希望这能帮到你。

您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - anber
这些只是不同的布局,你只需要使用一个MainActivity,在其中决定要使用哪个布局。 - glm9637
看起来它会工作,但是它使用不同的sourceSets破坏了flavors的想法,我应该手动关注哪个xml将被选择,而不是依赖于androidPlugin。 - anber

1

请提供您的paidbutton XML标签和MainActivity.java类的导入。

您可能使用了错误的资源导入,例如import android.R;而不是import my_package.R;


我在导入中没有R。 - anber
你的函数在代码中的哪里?在setContentView()方法之前还是之后?编译器无法找到R符号,因为你试图在其初始化之前使用它。 - Alexis Burgos
编译器可以找到R,但在R文件中,免费应用程序版本中没有R.id.paidbutton,而付费应用程序版本中存在R.id.paidbutton。这就是为什么付费应用程序版本可以成功组装,但免费应用程序版本无法成功的原因。 - anber
嗯,在你的Java示例中,你没有使用正确的R类。添加这个导入:"import company.com.myapplication.R"。 - Alexis Burgos
很抱歉,但我觉得您似乎并没有真正理解这个问题。我有两个带有company.com.myapplication.R包的R文件,一个文件中有R.id.paidbutton,而另一个文件中则没有。当我使用import company.com.myapplication.R时,它会同时导入这两个文件。 - anber
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接