为Android应用程序创建一个属性加载器

时间:2014-07-08 16:18:56

标签: java android sharedpreferences properties-file

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

在java中,我会做一个类似于以下我在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中有一些叫做SharedPreferences的东西,我已经在我的应用程序中使用了它。虽然我从不使用SharedPreferences直接在文件中更改变量信息,但仅使用应用程序的代码。

Android应用程序中最好的选择是什么?

因为我想要实现的是,更好地用属性加载器代表,它可以保存我不想在我的java代码中硬编码的东西。

2 个答案:

答案 0 :(得分:1)

您可以使用xml文件来存储您的配置,访问方式与作为标记的键和作为标记值的值相同。

例如 -

Path = yourapp / res / xml / RememberMeServer.xml

RememberMeServer.xml内容 -

<?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"));

类XMLData.java - (此类包含按键访问值的逻辑)

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

注意:

您可以更改文件RememberMeServer.xml中任意键的任何值。 这提供了您不必担心获取密钥保存值的灵活性。无论值是什么,方法都会通过键返回这些值。

SharedPreferences也是一件好事,但正如你所说,你有很多变量变化很多,所以最好的解决方案是将它们全部放在xml文件中,并在需要时访问它们。您可以根据要求更改任何值,但仍然是特定于内容的。整个逻辑集中在一个xml文件中,您可以查看和更改单个文件以修改任何值。

答案 1 :(得分:0)

选项1:应用资源

我真的不明白为什么你没有使用正常的应用资源?根据您的描述,这正是您所寻找的。您可以在那里指定所有类型的值,诸如ip和port之类的东西以及其他重要值应始终仍然在资源中。例如,如果你需要某个整数,你可以在 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>

或者可以在 res / values / strings.xml

中定义字符串
<?xml version="1.0" encoding="utf-8"?>
<resources>

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

</resources>

您在这些资源中定义的所有值都可以在以后加载:

Resources resources = getResources();
int someInteger = resources.getInteger(R.integer.some_integer);
String someString = resources.getString(R.string.some_string);

您可以在the official documentation中找到有关应用资源的更多信息。


选项2:SharedPreferences

另一种选择当然是SharedPreferences。在内部,SharedPreferences会保存到File。但我想这不是你想要的,因为它仍然需要你对所有初始值进行硬编码。


选项3:奇特的东西

如果你愿意的话,我也可以像这样拍一些喜欢的东西:

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

@Resource(id = R.integer.some_integer)
private int someInteger;

正如您所看到的,它使用反射和注释来加载资源值。可能非常方便,可能正是您正在寻找的。您可以通过调用以下内容从Object加载所有带注释的值:

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!");
    }
}