简体   繁体   English

无法解析不同风味android studio的方法'getAllUserGroupByName()'

[英]Cannot resolve method 'getAllUserGroupByName()' of different flavor android studio

Consider I am having two product flavor in my android project named 'local' & 'international'. 考虑我在我的android项目中有两个产品风味名为'local'和'international'。 I am just giving a skeleton of my situation, so kindly ignore other mistakes. 我只是给出了我的情况的骨架,所以请不要理会其他错误。 Consider I have already different source Set for different flavor. 考虑到我已经有不同的源Set为不同的味道。

Now in my 'local' flavor I just need the one method as mentioned below. 现在我的'本地'味道我只需要下面提到的一种方法。

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

While in my international flavor I also need additional feature to get the user in a group by its name also. 虽然在我的国际风格,我还需要其他功能,以使用户也可以通过其名称进入组。 So having two methods. 所以有两种方法。

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

But the problem is, I am having a single activity from where I am calling that method. 但问题是, 我正在调用该方法的单个活动。 When I am calling getAllUserGroupByName() method from activity it will compile if current flavor is ' international ' but it will not compile on ' local ' flavor as it does not contain that method. 当我从activity调用getAllUserGroupByName()方法时,如果当前flavor是' international ',它将编译,但它不会在' local '上编译,因为它不包含该方法。

I tried calling this method by wrapping in if condition like below, 我尝试通过如下条件包装来调用此方法,

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

But it's not working too. 但它也不起作用。

I don't want the following solution. 我不想要以下解决方案。

  • Two activity for each flavors. 每种口味的两种活动。
  • I already solved it by combining both interface in a single interface. 我已经通过在单个界面中组合两个接口来解决它。 (which is also valid as it does not contain any implementation). (这也是有效的,因为它不包含任何实现)。

Updated 更新

After some research and answer given by @manouti 经过@manouti的一些研究和回答

The issue is that Java is a statically typed language, so placing an if condition does not mean that the compiler will avoid checking the code with the getAllUserGroupByName invocation. 问题是Java是一种静态类型语言,因此放置if条件并不意味着编译器将避免使用getAllUserGroupByName调用来检查代码。

So is there any way that build system can ignore the particular code according to flavor for code compilation? 那么构建系统是否可以根据代码编译的风格忽略特定代码?

OR 要么

any Android studio IDE tool or feature that will discard the particular code according to flavor for compilation. 任何Android工作室IDE工具或功能,将根据编译风格丢弃特定代码。

There are several ways to do it. 有几种方法可以做到这一点。 Of course you can write two different Activity classes as the other answer mentioned, and place them in each flavor's source set, and that would work perfectly fine. 当然,你可以像提到的另一个答案一样编写两个不同的Activity类,并将它们放在每个flavor的源集中,这样就可以了。 But I assume you don't really want to do this because it would be an overkill to duplicate the code with possibly very little change between the two versions. 但我认为你并不是真的想要这样做,因为复制代码可能是一种过度杀伤,两个版本之间的变化可能很小。

Here are two ways I can think of that allow you to keep only one Activity class (ie in the main source set): 以下是我能想到的两种方法,允许您只保留一个Activity类(即在主源集中):

  1. Use reflection to call the method getAllUserGroupByName if it is defined. 如果已定义,则使用反射调用方法getAllUserGroupByName The details of this approach are very well illustrated in this post . 这篇文章的细节在这篇文章中有很好的说明。 The issue is that Java is a statically typed language, so placing an if condition does not mean that the compiler will avoid checking the code with the getAllUserGroupByName invocation. 问题是Java是一种静态类型语言,因此放置if条件并不意味着编译器将避免使用getAllUserGroupByName调用来检查代码。 With this solution, you can use reflection to check if the method is defined, and if so you can call it reflectively. 使用此解决方案,您可以使用反射来检查方法是否已定义,如果已定义,则可以反射性地调用它。

  2. Another solution which IMO is cleaner than using reflection code is to encapsulate the logic of retrieving user group information in its own class and in the same package, say UserGroupLoader , and define two versions of this class, one for each flavor. IMO比使用反射代码更清洁的另一个解决方案是将用户组信息的检索逻辑封装在自己的类和同一个包中,比如UserGroupLoader ,并定义该类的两个版本,每个版本对应一个版本。 In the local flavor, the implementation would return a dummy result (eg an empty list of users) and in the international flavor it would use the actual code of loading the users: 在本地风格中,实现将返回虚拟结果(例如,空的用户列表),并且在国际风格中它将使用加载用户的实际代码:

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

You can also control the scope of the logic to encapsulate in this class. 您还可以控制要封装在此类中的逻辑范围。 For example, instead of just returning the user group list, you can have it return the combined result of both all users (first method in UserDao ) and all users by group name (only applies to the implementation for international flavor). 例如,您可以让它返回所有用户( UserDao第一个方法)和按组名称的所有用户(仅适用于国际风味的实现)的组合结果,而不仅仅返回用户组列表。 This makes the code more readable, because just having a method that returns dummy data for one flavor may seem to be counter-intuitive for readers. 这使得代码更具可读性,因为只有一个返回一种风格的虚拟数据的方法对于读者来说似乎是违反直觉的。

You could create interface containing only getAllUserGroupByName() method and make international version extend it. 您可以创建仅包含getAllUserGroupByName()方法的接口,并使国际版本扩展它。

With this you can do instanceof check on userDao. 有了这个,您可以对userDao进行instanceof检查。

Interface with getAllUserGroupByName() method (it should be put in common source set): getAllUserGroupByName()方法的接口(它应该放在公共源集中):

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

Make UserDao in international version extend it: 使UserDao在国际版中扩展它:

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

And in your activity check if UserDao is instance of InternationalInterface . 并在您的活动中检查UserDao是否是InternationalInterface实例。 If statement is going to be true only for the application built with international flavor. 如果声明仅适用于使用国际风格构建的应用程序。 Now you dont even need to use BuildUtils anymore. 现在你甚至不需要再使用BuildUtils了。

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

What about making your current activity abstract with a method like: 如何通过以下方法使您的当前活动抽象:

protected abstract void onGetAllUserGroupByName();

and then extending it with two version of the same activity like 然后用相同活动的两个版本扩展它

public class MyActivityImpl extends MyActivity {

     @Override
     protected void onGetAllUserGroupByName() {
         ...
     } 
}

When the flavor is local then the overridden method is empty and when it is international it will be: 当味道是本地的时候,被覆盖的方法是空的,当它是国际的时 ,它将是:

@Override
protected void onGetAllUserGroupByName() {           
    getAppDatabase().UserDao().getAllUserGroupByName();
} 

You won't need to replicate any of your features already present in the parent activity. 您无需复制父活动中已存在的任何功能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM