【问题标题】:Android, Best way to provide app specific constants in a library project?Android,在库项目中提供应用程序特定常量的最佳方式?
【发布时间】:2012-04-03 10:04:36
【问题描述】:

我正在为许多 Android 应用程序创建一个库项目。 这些应用程序都有一些我希望包含在库项目中的通用功能,但库项目功能需要使用特定于应用程序的常量

所以我正在寻找一种方法来为库函数提供常量名称并允许每个应用程序定义它们

特定应用常量的示例以及它在库项目中的使用方式

public class AppConstants {
    public static final long APP_ID = 6;//Needs to be set for each app
}

public static long getCurrentAppId(Context context) {
    return getLongPreference(context, CURRENT_APP_ID_KEY, AppConstants.APP_ID);
}

这只是需要为每个应用程序定义大量库函数的大约 60 个常量的一个示例

显然我通常只导入/包含项目特定的 app_constants.java 文件,但这在库项目文件中是不可能的,因为它没有关于特定应用程序的线索(正确)

那么让每个特定应用覆盖常量的最佳方法是什么?

更新 我花了很长时间才决定为我提供的最佳答案中的哪一个最适合我的需求(谢谢大家)最后我选择了 xml 解决方案。我不是特别喜欢它,因为它弄乱了我的应用程序资源,我确实认真考虑过使用界面解决方案,但 xml 解决方案确实很好用

【问题讨论】:

    标签: android shared-libraries


    【解决方案1】:

    在您的库项目中将它们定义为枚举,例如

    public enum Planet { MERCURY, VENUS, MARS }
    

    Android 本身采用了另一种方法,可怕的常量接口,例如,

    interface Planets {
      static final int MERCURY = 1;
      static final int VENUS = 2;
      ...
    }
    

    然而,这是一个众所周知的 Java 反模式(常量接口,我引用的 Effective Java 中有详细介绍,

    常量接口模式是对接口的不良使用。那一个 类在内部使用一些常量是一个实现细节。 实现一个常量接口会导致这个实现细节 泄漏到类的导出 API 中。对它没有任何影响 一个类的用户认为该类实现了一个常量接口。在 事实上,它甚至可能使他们感到困惑。更糟糕的是,它代表了一种承诺:如果 在未来的版本中,该类被修改,使其不再需要 要使用常量,它仍然必须实现接口以确保 二进制兼容性。如果一个非final类实现了一个常量 接口,它的所有子类的命名空间都会被污染 通过接口中的常量。

    如果您出于某种原因需要常量具有 int 值,并且在枚举上调用 toString() 是不够的,您可以为枚举提供额外的信息,例如,

    public enum ZipCode {
      LYNNWOOD(98036), SAN_JOSE(95112), ...;
    
      private int zipCode;
    
      private ZipCode(int zipCode) { this.zipCode = zipCode; }
    
      public int getZipCode() { return zipCode; }
    }
    

    请注意,枚举的性能略低于整数常量,但从代码组织和清晰度的角度来看,它们要优越得多。

    【讨论】:

      【解决方案2】:

      我不知道有什么好的架构可以做到这一点,但它肯定会这样工作:

      在你的库中定义一些基类

      // class, enum or whatever you want it to be. 
      class BaseConstants {
          // use some real singleton instead
          public static final BaseConstants instance = new BaseConstants();
      
          // define those values - sadly static inheritance does not work
          private static final int APP_ID = 0;
          private static final int CURRENT_APP_ID_KEY = 24;
      
          // so we have to do that via methods
          protected int getAppId() {
              return APP_ID;
          }
          protected int getAppIdKey() {
              return CURRENT_APP_ID_KEY;
          }
      }
      

      让每个想要自定义的 Activity 实现它

      class App1Constants extends BaseConstants {
          public static final App1Constants instance = new App1Constants();
      
          private final static int APP_ID = 1;
      
          // want a different APP_ID here.
          protected int getAppId() {
              return APP_ID;
          }
      
          // getAppIdKey not implemented here, uses default
      }
      

      将该类用作库常量的上下文

      class Library {
          public static long getCurrentAppId(Context context, BaseConstants settings) {
              return getLongPreference(context, settings.getAppIdKey(), settings.getAppId());
          }
      }
      

      活动应该是这样的

      class myActivity extends Activity {
          // each Activity can implement it's own constants class and overwrite only some values
          private static final BaseConstants CONSTANTS = App1Constants.instance;
      
          private void whatever() {
              long appId = Library.getCurrentAppId(this, CONSTANTS);
          }
      }
      
      class myActivity2 extends Activity {
          // or could just use the default ones
          private static final BaseConstants CONSTANTS = BaseConstants.instance;
      
          private void whatever() {
              long appId = Library.getCurrentAppId(this, CONSTANTS);
          }
      }
      

      这个架构有点丑,但至少可以工作

      【讨论】:

        【解决方案3】:

        选项 #1 在每个项目中扩展您的 AppConstants 类

        更好的选择#2 使用 XML 资源定义常量

        <?xml version="1.0" encoding="utf-8"?>
        <resources>
        <item type="integer" name="app_id" format="integer">6</item>
        </resources>
        

        然后您可以通过

        检索它们
        Context.getResources().getInteger(R.integer.app_id);
        

        将 xml 文件添加到每个项目中的资源中,仅使用您需要的不同值

        【讨论】:

        • 如果您在库和应用程序中定义具有相同 id 的资源,如果存在,则从应用程序获取值,否则从库获取值。因此,对于您想要覆盖每个应用程序的值,这是一个非常好的方法。由于它使用资源系统,您甚至可以为每个配置(横向与纵向等)做值
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-07-12
        • 2016-05-23
        • 2013-08-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多