有没有办法为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.
}
// ...
}
答案 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,这是example和another one。
我希望它对你有所帮助!
答案 2 :(得分:0)
XML序列化机制在Android上并不一致。我会推荐Json,可能还有Gson库。