开发者

Keeping it modular in android - Dividing resources in a good way

Background

I'm trying to keep an app which is as modular as possible.

The app will have have tasks which it performs on different intervals. My goal is to make it as easy possible to add new tasks with minimal understanding of the underlying architecture and without having to modify other files but at the same time not over complicating the code.

It would be perfect if all you needed to do to add a new task is to create the file and that's it.

This will require loading the tasks in runtime which I don't really like, I could live with a single place where all the registration is done (this also enabled toggling of the task)

Right now I've have an abstract task class which has a piece of static code which registers all tasks (basically adds them to a list).

Problem

Each task will have their own set of preferences and possibly resources.

Dividing strings and array is pretty easy by using prefixes for the names but the main issue comes with the preferences.

Right now I'm using a PreferenceActivity to display my preferences.

The general settings are loaded from an XML file. Each task's preferences are located in a separate PreferenceScreen. All tasks have only one thing common and that is an "Enabled" checkbox.

I don't want to store all the preferences in one file as it has the possibility to get quite messy that way.

Current solution

Right now each task have a method setupPreferences(PreferenceScreen) in which they can add whatever options they want. This however has the downside of being programmatically which is not all that bad but I'd like to avoid that if possible.

Desired solution

The optimal solution would be if each task could have their own XML file which is loaded and added to the root PreferenceScreen, as far as I know however this is not possible, the only way to load it is into a PreferenceActivity.

Other notes

If anyone has any other suggestions on dividing resources in android feel free to share them :)

Thanks

Nicklas


Clarification

The tasks I'm talking about are never 开发者_高级运维third party, they will internal only. This is more of a way to early on get a good structure of this app.


By using reflection I'm calling PreferenceManager.inflateFromResource(Context, int, PreferenceScreen) to create a PreferenceScreen from my XML files.

String resources are separated in separate files and prefixed with taskname_

Here is the code for inflating the PreferenceScreen, it should be placed in a PreferenceActivity:

/**
 * Inflates a {@link android.preference.PreferenceScreen PreferenceScreen} from the specified
 * resource.<br>
 * <br>
 * The resource should come from {@code R.xml}
 * 
 * @param resId The ID of the XML file
 * @return The preference screen or null on failure.
 */
private PreferenceScreen inflatePreferenceScreenFromResource(int resId) {
    try {
        Class<PreferenceManager> cls = PreferenceManager.class;
        Method method = cls.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);
        return (PreferenceScreen) method.invoke(getPreferenceManager(), this, resId, null);         
    } catch(Exception e) {
        Log.w(LOG_TAG, "Could not inflate preference screen from XML", e);
    }

    return null;
}

Here is an example of how to use it:

package com.example;

import java.lang.reflect.Method;

import com.example.R;

import android.os.Bundle;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.preference.PreferenceScreen;
import android.util.Log;


public class ExamplePreferenceActivity extends PreferenceActivity {
    public static final String PREFERENCE_NAME = "ExamplePreferences";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Sets the preference name
        PreferenceManager pm = getPreferenceManager();
        pm.setSharedPreferencesName(PREFERENCE_NAME);

        // Adds default values and the root preference screen
        PreferenceManager.setDefaultValues(this, PREFERENCE_NAME, MODE_PRIVATE, R.xml.preferences_layout, false);
        addPreferencesFromResource(R.xml.preferences_layout);

        PreferenceScreen root = getPreferenceScreen();

        // Includes R.xml.other_preferences_layout and adds it to the bottom of the root preference screen
        PreferenceScreen otherPreferenceScreen = inflatePreferenceScreenFromResource(R.xml.other_preferences_layout);
        root.addPreference(otherPreferenceScreen);
        PreferenceManager.setDefaultValues(this, PREFERENCE_NAME, MODE_PRIVATE, R.xml.other_preferences_layout, false);
    }

    /**
     * Inflates a {@link android.preference.PreferenceScreen PreferenceScreen} from the specified
     * resource.<br>
     * <br>
     * The resource should come from {@code R.xml}
     * 
     * @param resId The ID of the XML file
     * @return The preference screen or null on failure.
     */
    private PreferenceScreen inflatePreferenceScreenFromResource(int resId) {
        try {
            Class<PreferenceManager> cls = PreferenceManager.class;
            Method method = cls.getDeclaredMethod("inflateFromResource", Context.class, int.class, PreferenceScreen.class);
            return (PreferenceScreen) method.invoke(getPreferenceManager(), this, resId, null);         
        } catch(Exception e) {
            Log.w(LOG_TAG, "Could not inflate preference screen from XML", e);
        }

        return null;
    }  
}

This example would use res/xml/preferences_layout.xml as the root and then add res/xml/other_preferences_layout.xml to the bottom of the root.


Not exactly an answer to your question, but might be interesting anyway: have a look at plugin API for Locale and Tasker: http://www.twofortyfouram.com/developer.html

Locale and Tasker are phone automation apps. Both are highly configurable and modular, they accept third party plugins to extend their functionality. Similar to your case, each plugin has unique preferences. Their solution to the problem is, each plugin brings its own preferences activity, accessible using specific intent action. There are UI guidelines so that preferences screens look consistent.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜