创建自定义XML数据类型?

时间:2011-12-04 21:31:01

标签: android xml

有没有办法为Android创建自定义XML数据类型?

我有一个类Model,其中包含我的实体的所有统计信息。我希望能够从xml类似地扩展Model类 - 好吧,像View一样exaclty。这可能吗?

示例:

<?xml version="1.0" encoding="utf-8"?>
<models xmlns:android="http://schemas.android.com/apk/res/android">
    <model name="tall_model"
        type="@string/infantry"
        stat_attack="5"
        >Tall Gunner</model>

    <model name="short_model"
        type="@string/infantry"
        stat_attack="3"
        ability="@resource/scout"
        >Short Gunner</model>

    <model name="big_tank"
        type="@string/vehicle"
        stat_attack="7"
        armour="5"
        >Big Tank</model>
</models>

我要上课的课程。

class Model [extends Object] {
    public Model(Context context, AttributeSet attrs) {
        // I think you understand what happens here.
    }
    // ...
}

3 个答案:

答案 0 :(得分:9)

使用精心选择的API的一些自定义代码,您可以模仿Android扩展布局XML文件的方式,并且仍然受益于Android的XML优化和好处,就像编译XML文件和引用自定义XML文件中的任意资源一样。您不能直接挂入现有的LayoutInflater,因为该类只能处理View的膨胀。为了使下面的代码能够工作,请将XML文件放在应用程序中的“res / xml”中。

首先,这是解析(编译的)XML文件并调用Model构造函数的代码。您可能希望添加一些注册机制,以便您可以轻松地为任何标记注册类,或者您可能希望使用ClassLoader.loadClass(),以便可以根据其名称加载类。

public class CustomInflator {
    public static ArrayList<Model> inflate(Context context, int xmlFileResId) throws Exception {
        ArrayList<Model> models = new ArrayList<Model>();

        XmlResourceParser parser = context.getResources().getXml(R.xml.models);
        Model currentModel = null;
        int token;
        while ((token = parser.next()) != XmlPullParser.END_DOCUMENT) {
            if (token == XmlPullParser.START_TAG) {
                if ("model".equals(parser.getName())) {
                    // You can retrieve the class in other ways if you wish
                    Class<?> clazz = Model.class;
                    Class<?>[] params = new Class[] { Context.class, AttributeSet.class };
                    Constructor<?> constructor = clazz.getConstructor(params);
                    currentModel = (Model)constructor.newInstance(context, parser);
                    models.add(currentModel);
                }
            } else if (token == XmlPullParser.TEXT) {
                if (currentModel != null) {
                    currentModel.setText(parser.getText());
                }
            } else if (token == XmlPullParser.END_TAG) {
                // FIXME: Handle when "model" is a child of "model"
                if ("model".equals(parser.getName())) {
                    currentModel = null;
                }
            }
        }

        return models;
    }
 }

有了这个,您可以将属性的“解析”放在Model类中,就像View一样:

public class Model {
    private String mName;
    private String mType;
    private int mStatAttack;
    private String mText;

    public Model(Context context, AttributeSet attrs) {
        for (int i = 0; i < attrs.getAttributeCount(); i++) {
            String attr = attrs.getAttributeName(i);
            if ("name".equals(attr)) {
                mName = attrs.getAttributeValue(i);
            } else if ("type".equals(attr)) {
                // This will load the value of the string resource you
                // referenced in your XML
                int stringResource = attrs.getAttributeResourceValue(i, 0);
                mType = context.getString(stringResource);
            } else if ("stat_attack".equals(attr)) {
                mStatAttack = attrs.getAttributeIntValue(i, -1);
            } else {
                // TODO: Parse more attributes
            }
        }
    }

    public void setText(String text) {
        mText = text;
    }

    @Override
    public String toString() {
        return "model name=" + mName + " type=" + mType + " stat_attack=" + mStatAttack + " text=" + mText;
    }
}

上面我通过字符串表示引用了属性。如果你想更进一步,你可以定义特定于应用程序的属性资源并使用它们,但这会使事情变得复杂(参见Declaring a custom android UI element using XML)。无论如何,所有资源设置和虚拟活动中的这个:

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    try {
        for (Model m : CustomInflator.inflate(this, R.xml.models)) {
            Log.i("Example", "Parsed: " + m.toString());
        }
    } catch (Exception e) {
        Log.e("Example", "Got " + e);
    }
}

你会得到这个输出:

I/Example ( 1567): Parsed: model name=tall_model type=Example3 stat_attack=5 text=Tall Gunner
I/Example ( 1567): Parsed: model name=short_model type=Example3 stat_attack=3 text=Short Gunner
I/Example ( 1567): Parsed: model name=big_tank type=Example2 stat_attack=7 text=Big Tank

请注意,您的XML文件中不能包含@resource/scout,因为resource不是有效的资源类型,但@string/foo可以正常工作。您还应该能够使用例如@drawable/foo对代码进行一些微不足道的修改。

答案 1 :(得分:1)

如果扩展现有的视图类,例如TextView,EditText,则可以在xml布局中调用它。

这是自定义组件的Android Reference

您也可以定义自定义xml attrubutes,这是exampleanother one

我希望它对你有所帮助!

答案 2 :(得分:0)

XML序列化机制在Android上并不一致。我会推荐Json,可能还有Gson库。