Android,在库项目中提供应用程序特定常量的最佳方法?

时间:2012-03-18 19:10:31

标签: android shared-libraries

我正在为许多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解决方案确实很好用

3 个答案:

答案 0 :(得分:20)

选项#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文件添加到每个项目的资源中,只需要不同的值

答案 1 :(得分:3)

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

在库中定义一些基类

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

该架构有点难看,但它至少可以起作用

答案 2 :(得分:1)

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

public enum Planet { MERCURY, VENUS, MARS }

android适当采用另一种方法,可怕的常量接口,比如,

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

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

  

常量接口模式是接口的不良使用。那个   class在内部使用一些常量是一个实现细节。   实现常量接口会导致此实现细节   泄漏到类的导出API中。它并不重要   类实现常量接口的类的用户。在   事实上,它甚至可能使他们感到困惑。更糟糕的是,它代表了一种承诺:如果   在将来的版本中,类被修改,以便它不再需要   要使用常量,它仍然必须实现接口以确保   二进制兼容性如果非最终类实现常量   接口,它的所有子类都会污染它们的名称空间   通过界面中的常量。

如果由于某种原因需要常量来获取int值,并且在枚举上调用toString()是不够的,你可以给enum一个额外的信息,比如

public enum ZipCode {
  LYNNWOOD(98036), SAN_JOSE(95112), ...;

  private int zipCode;

  private ZipCode(int zipCode) { this.zipCode = zipCode; }

  public int getZipCode() { return zipCode; }
}

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