Java 为android应用程序创建属性加载器

Java 为android应用程序创建属性加载器,java,android,sharedpreferences,properties-file,Java,Android,Sharedpreferences,Properties File,我正在开发一个android应用程序,有几个变量可能需要更改,但我不想重新编译android应用程序并将其部署到android智能手机中 在java中,我将执行一个propertyloader,就像我以前在java中所做的那样: public class PropertyLoader { private static Properties props = null; /** * Method initializes the PropertyLoader by rea

我正在开发一个android应用程序,有几个变量可能需要更改,但我不想重新编译android应用程序并将其部署到android智能手机中

在java中,我将执行一个propertyloader,就像我以前在java中所做的那样:

public class PropertyLoader {

    private static Properties props = null;

    /**
     * Method initializes the PropertyLoader by reading all configuration settings
     * from the RememberMeServer.conf file.
     */
    public static void initializeProperties() {
        String propFile = getCatalinaDirectory() + "RememberMeServer.conf";

        System.out.println(propFile);

        File configFile = new File(propFile);
        InputStream inputStream = null;
        try {
            inputStream = new FileInputStream(configFile);
        } catch (FileNotFoundException e1) {
            e1.printStackTrace();
        }

        props = new Properties();

        try {
            props.load(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * Returns a string value from the configuration file.
     *
     * @param  key  a string which represents the key of the requested value in the configuration file
     * @return      the value of the requested key from the property file as a string or null if the
     *              requested key could not be found.
     */
    public static String getStringValue(String key) {
        return props == null ? null : props.getProperty(key);
    }

    /**
     * Returns an int value from the configuration file.
     *
     * @param  key  a string which represents the key of the requested value in the configuration file
     * @return      the value of the requested key from the property file as an int or null if the
     *              requested key could not be found.
     */
    public static Integer getIntValue(String key) {
        return props == null ? null : Integer.valueOf(props.getProperty(key));
    }

    /**
     * Returns the directory of the project�s workspace as a string
     *
     * @return      Returns the directory of the project�s workspace as a string
     */
    public static String getWorkspaceDirectory() {
        URL url = PropertyLoader.class.getClassLoader().getResource(
                "hibernate.cfg.xml");
        return url.getFile().substring(0,
                url.getFile().lastIndexOf("hibernate.cfg.xml"));
    }

    /**
     * Returns the directory of the servlet container catalina directory as a string
     *
     * @return      Returns the directory of the servlet container catalina directory as a string
     */
    public static String getCatalinaDirectory() {
        String workspace = getWorkspaceDirectory();
        return workspace
                .substring(0, workspace.lastIndexOf("RememberMeServer"));
    }
}
虽然在android中,我已经在应用程序中使用了一种叫做SharedReferences的东西。虽然我从未使用SharedReferences直接在文件中更改变量信息,但仅从应用程序的代码中更改

android应用程序的最佳替代方案是什么

因为对我来说,我想要实现的是一个属性加载器,它可以更好地表示我不想在java代码中硬编码的内容。

选项1:应用程序资源 我真正不明白的是,为什么你不使用普通的应用程序资源?从你描述的情况来看,这正是你想要的。您可以在其中指定所有类型的值,并且像ip和端口之类的内容以及其他重要的值应该始终在资源中。例如,如果您需要某个整数,您可以在res/values/ints.xml中定义一个整数:

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <integer name="some_integer">27</integer>
    <integer name="another_integer">42</integer>   

</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="some_string">Some Text</integer>
    <string name="another_string">qwerty</integer>

</resources>
您可以在中找到有关应用程序资源的更多信息


选项2:共享引用 当然,另一个选项是
SharedReferences
。在内部,
SharedReferences
保存到
文件中。但我想这不是您想要的,因为它仍然需要您硬编码所有初始值


选项3:花哨的东西 如果你愿意的话,我也可以这样做:

@Resource(id = R.string.some_string)
private String someString;

@Resource(id = R.integer.some_integer)
private int someInteger;
如您所见,它使用反射和注释来加载资源值。可能非常方便,也可能正是您想要的。通过调用以下命令,可以从一个
对象
加载所有带注释的值:

ResourceLoader.load(context, object);
这个
ResourceLoader
的源代码并不新奇,但是目前它只支持加载字符串和整数资源,但是扩展它应该没有问题:

public class ResourceLoader {

    // This is the definition of the @Resource annotation
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface Resource {
        public int id();
    }

    public static void load(Context context, Object target) {
        final Class<?> cls = target.getClass();

        // This gets all declared fields, meaning all inherited fields are ignored
        final Field[] fields = cls.getDeclaredFields();

        for(Field field : fields) {
            field.setAccessible(true);

            final Class<?> type = field.getType();

            // We check if the Annotation is present
            if(field.isAnnotationPresent(Resource.class)) {
                final Resource annotation = field.getAnnotation(Resource.class);
                final int id = annotation.id();

                // And if it is present use the id and type of the field to load
                // the correct resource
                final Object value = loadValue(context, id, type);

                try {
                    // Finally we set the new value to the field
                    field.set(target, value);
                } catch (IllegalAccessException e) {
                    throw new IllegalStateException("Could not set resource value to field " + field, e);
                }
            }
        }
    }

    private static Object loadValue(Context context, int id, Class<?> type) {
        final Resources resources = context.getResources();

        if(int.class.isAssignableFrom(type) || Integer.class.isAssignableFrom(type)) {
            return resources.getInteger(id);
        }

        if(String.class.isAssignableFrom(type)) {
            return resources.getString(id);
        }

        throw new IllegalStateException("Type \"" + type + "\" is not supported!");
    }
}
公共类资源加载器{
//这是@Resource注释的定义
@保留(RetentionPolicy.RUNTIME)
@目标(ElementType.FIELD)
公共@接口资源{
公共int id();
}
公共静态无效加载(上下文、对象目标){
最终类cls=target.getClass();
//这将获取所有声明的字段,这意味着忽略所有继承的字段
最终字段[]字段=cls.getDeclaredFields();
用于(字段:字段){
字段。setAccessible(true);
最终类类型=field.getType();
//我们检查注释是否存在
if(field.isAnnotationPresent(Resource.class)){
最终资源注释=field.getAnnotation(Resource.class);
final int id=annotation.id();
//如果存在,则使用要加载的字段的id和类型
//正确的资源
最终对象值=加载值(上下文、id、类型);
试一试{
//最后,我们将新值设置到字段
设置(目标、值);
}捕获(非法访问例外e){
抛出新的IllegalStateException(“无法将资源值设置为字段”+字段,e);
}
}
}
}
私有静态对象loadValue(上下文上下文、int-id、类类型){
final Resources=context.getResources();
if(int.class.isAssignableFrom(类型)| | Integer.class.isAssignableFrom(类型)){
返回resources.getInteger(id);
}
if(String.class.isAssignableFrom(type)){
返回resources.getString(id);
}
抛出新的IllegalStateException(“不支持类型\”+Type+“\”);
}
}
您可以使用xml文件存储配置,并以与键为标记、值为标记值相同的方式访问

比如说- Path=yourapp/res/xml/remembermserver.xml

remembermserver.xml
contents-

<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
    <key>day</key>
    <integer>1</integer>
    <key>hour</key>
    <integer>12</integer>
    <key>minute</key>
    <integer>10</integer>
    <key>second</key>
    <integer>14</integer>
    <key>background</key>
    <string>Graphic_6_7_Red</string>
    <key>Online</key>
    <true/>   
</dict>
</plist>
类XMLData.java- (此类包含通过键访问值的逻辑)

publicstringgetvalue(字符串键){
int start=this.xmldoc.indexOf(“+key+”);
如果(开始==-1)
返回“”;
字符串xmldoc2=this.xmldoc.substring(start);
start=xmldoc2.indexOf(“”);
xmldoc2=xmldoc2.子字符串(开始);
xmldoc2=xmldoc2.子串(6);
start=xmldoc2.indexOf(“>”);
xmldoc2=xmldoc2.子字符串(开始+1);

int end=xmldoc2.indexOf("你想保存变量状态还是将文件保存到设备上?Android为这两者都提供了内置解决方案。我想存储对应用程序功能至关重要的静态信息,但它不会以编程方式添加或删除变量。哪些是?共享参考将满足你的需要。我只想阅读更多文档选项。如果这不符合您的需要,也许可以查看一下Parse SDK,看看它是否适合您。我使用并理解SharedReferences。但我想更改文件中的变量。因此,我可以更改IP和端口之类的内容,应用程序将使用它们与服务器进行通信,即使SharedReferences存储在文件中,您也可以更改每次都要像属性文件一样替换文件这很有趣,你的答案基本上可以归结为我在回答中试图表达的同一点。使用应用程序资源是最好的选择,尽管我个人不喜欢XML方法。使用
XmlPullParser
看起来很混乱…只是
getResources().getString(…)
或者类似的东西在我看来更干净,更不容易出错。是的,但是如果你想用元素保持清晰的层次结构
<?xml version="1.0" encoding="UTF-8"?>
<plist version="1.0">
<dict>
    <key>day</key>
    <integer>1</integer>
    <key>hour</key>
    <integer>12</integer>
    <key>minute</key>
    <integer>10</integer>
    <key>second</key>
    <integer>14</integer>
    <key>background</key>
    <string>Graphic_6_7_Red</string>
    <key>Online</key>
    <true/>   
</dict>
</plist>
String day, hour, minute, second, background;
boolean status;

int resId = getResources().getIdentifier("xml/" + RememberMeServer, 
            "string", getActivity().getPackageName());
XmlPullParser xpp0 = getResources().getXml(resId);
XMLData xml = new XMLData(xpp0);
day = (xml.getValue("day"));
hour= (xml.getValue("hour"));
second= (xml.getValue("second"));
minute= (xml.getValue("minute"));
background= (xml.getValue("Graphic_6_7_Red"));
status= (xml.checkFieldPresence("Online"));
public String getValue(String key) {
        int start = this.xmldoc.indexOf("<key>"+ key + "</key>");

        if(start == -1)
            return "";


        String xmldoc2 = this.xmldoc.substring(start);

        start = xmldoc2.indexOf("</key>");
        xmldoc2 = xmldoc2.substring(start);

        xmldoc2 = xmldoc2.substring(6);

        start = xmldoc2.indexOf(">");
        xmldoc2 = xmldoc2.substring(start + 1);

        int end = xmldoc2.indexOf("</");

        xmldoc2 = xmldoc2.substring(0, end);
        return xmldoc2;

    }

public boolean checkFieldPresence(String key)
{
        int start = this.xmldoc.indexOf(key + "</key>");

        if(start == -1)
            return false;
        else
            return true;
}