无法解析不同口味的Android工作室的方法'getAllUserGroupByName()'

2022-09-04 22:03:18

考虑到我在我的Android项目中有两种产品风格,分别名为“本地”和“国际”。我只是在给出我的情况的骨架,所以请忽略其他错误。考虑到我已经为不同的口味设置了不同的源代码。

现在,在我的“本地”风格中,我只需要下面提到的一种方法。

// local flavor file
interface UserDao {
    List<User> getAllUser();
}

虽然在我的国际风格中,我还需要额外的功能来按其名称将用户放入组中。所以有两种方法。

// international flavor file
interface UserDao {
    List<User> getAllUser();
    List<User> getAllUserGroupByName();
}

但问题是,我从调用该方法的位置有一个活动。当我从活动中调用方法时,如果当前风格是“国际”,它将编译,但它不会编译“本地”风格,因为它不包含该方法。getAllUserGroupByName()

我尝试通过包装如下条件来调用此方法,

// BuildUtils is my helper class to get current flavor check easily.
if (BuildUtils.isInternational()) {
      getAppDatabase().UserDao().getAllUserGroupByName();
}

但它也不起作用。

我不想要以下解决方案。

  • 每种口味两种活动。
  • 我已经通过将两个接口组合在一个接口中解决了这个问题。(这也是有效的,因为它不包含任何实现)。

更新

经过一些研究和@manouti给出的答案

问题在于 Java 是一种静态类型的语言,因此放置 if 条件并不意味着编译器将避免使用 getAllUserGroupByName 调用来检查代码。

那么,有没有办法让构建系统根据代码编译的风格忽略特定的代码呢?

任何Android工作室IDE工具或功能,它将根据风格丢弃特定代码进行编译。


答案 1

有几种方法可以做到这一点。当然,您可以编写两个不同的 Activity 类,如另一个答案所述,并将它们放在每种口味的源代码集中,这样可以很好地工作。但是我假设你真的不想这样做,因为复制代码在两个版本之间可能几乎没有变化是一种过度的伤害。

以下是我能想到的两种方法,允许您只保留一个活动类(即在主源代码集中):

  1. 使用反射来调用该方法(如果已定义)。这种方法的细节在这篇文章中得到了很好的说明。问题在于Java是一种静态类型语言,因此放置条件并不意味着编译器将避免使用调用检查代码。使用此解决方案,可以使用反射来检查方法是否已定义,如果是这样,则可以反射地调用它。getAllUserGroupByNameifgetAllUserGroupByName

  2. IMO 比使用反射代码更干净的另一个解决方案是将检索用户组信息的逻辑封装在自己的类和同一包中,例如 ,并定义此类的两个版本,每种类型一个版本。在本地风格中,实现将返回一个虚拟结果(例如,一个空的用户列表),在国际风格中,它将使用加载用户的实际代码:UserGroupLoader

    public class UserGroupInfoLoader {
        public List<User> getAllUserGroupByName() {
            // for international flavor, call UserDao.getAllUserGroupByName
            // for local flavor, return empty list (you may even use the Optional class as a return type instead of List<User>)
        }
    }
    

您还可以控制要封装在此类中的逻辑的作用域。例如,您可以让它按组名返回所有用户(中的第一个方法)和所有用户的组合结果(仅适用于国际风味的实现),而不是只返回用户组列表。这使得代码更具可读性,因为仅仅有一个方法返回一种风格的虚拟数据对于读者来说似乎是违反直觉的。UserDao


答案 2

您可以创建仅包含方法的接口,并使国际版本扩展它。getAllUserGroupByName()

有了这个,你可以在userDao上进行实例检查。

与方法的接口(应放在公共源代码集中):getAllUserGroupByName()

interface InternationalInterface {
    List<User> getAllUserGroupByName();
}

使用户道在国际版中扩展它:

// international flavor file
interface UserDao extends InternationalInterface {
    List<User> getAllUser();
}

并在您的活动中检查UserDao是否是.if 语句仅对具有国际风格构建的应用程序为真。现在你甚至不再需要使用BuildUtils。InternationalInterface

UserDao userDao = getAppDatabase().UserDao();
if (userDao instanceof InternationalInterface) {
    ((InternationalInterface)userDao).getAllUserGroupByName();
}

推荐