How to create an "overrideable" configuration in java?
I have two versions of an app based on a common code library project.
The library uses some constant values to determine some runtime configurations, and now I want each app to have a slightly different configuration.
Simplified problem: I have a boolean field in my library project that determines whether or not I display ads in my app. By defaul开发者_Go百科t it's true (as defined in the Library project), and App version A is fine with that. But I need App version B to be add free, so I need to set that value to false.
How can I implement this so that I can essentially override the configuration value in the Library project from the projects that reference the library?
I can change both the library implementation and the referencing project's implementation.
Edit
Also, the configuration boolean only affects the library code's behavior.
A bit late, but I found that this solution works well in my projects. It uses the Android Application
class to set a singleton configuration instance that overrides the config of the library.
Config
and ConfigInstance
below are in the library.
public final class Config {
public static final boolean VAL;
private Config() {}
static {
// this will be overridden by previous calls to
// ConfigInstance.getInstance()
final ConfigInstance confInstance = ConfigInstance.getInstance(ConfigInstance.DEFAULT_VAL);
VAL = confInstance.val;
}
}
// Singleton helper class, be sure not to reference the Config class
// here so that it is not loaded
public final class ConfigInstance {
private static volatile ConfigInstance instance = null;
static final boolean DEFAULT_VAL = false;
public final boolean val;
private ConfigInstance(final boolean val) {
this.val = val;
}
// thread safe singleton generator
public static ConfigInstance getInstance(final boolean val) {
ConfigInstance result = instance;
if (result == null) { // 1st check no lock
synchronized (ConfigInstance.class) {
result = instance;
if (result == null) { // 2nd check with lock
instance = result = new ConfigInstance(val);
}
}
}
return result;
}
}
Add the following class to each of the higher level projects, making sure to set the "name" field in the <application>
tag in the manifest.
public class ApplicationWrapper extends Application {
static {
// this will set the singleton ConfigInstance first, ie. before
// the library static block is executed; forcing it to use the
// values here
ConfigInstance.getInstance(true);
}
}
With this, Config.VAL
will be set to true
in the project.
Just encapsulate the variable in a getter function (getFoo()) and use it through your code. Then override the getter in your subclasses.
Other options include getting the Android package name from your context and making a decision based on that, or pulling a piece of meta-data from your manifest.
You shouldn't be using a constant value in this case. What you should do is create an abstract class with a getter in it and then extend that interface like so:
public abstract class Config {
public abstract int getValue();
}
public class AppA extends Config {
private static final int value = 1;
@Override
public int getValue(){
return value;
}
}
public class AppB extends Config {
private static final int value = 2;
@Override
public int getValue(){
return value;
}
}
EDIT: OP added that he needs the configuration value in his library code. I suggest still using this code, but then adding a setter in the library code to take the value returned from this getter in the application setup code.
精彩评论