Создать собственный тип данных XML?

Есть ли способ создать пользовательский тип данных XML для Android?

У меня есть Model класса, которая содержит всю статистику моих объектов. Я хочу, чтобы иметь возможность раздуть Model класс от xml аналогичным – ну, exaclty, как и View's do. Это возможно?

Пример:

 <?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. } // ... } 

С помощью специального кода, использующего тщательно отобранные API, вы можете имитировать способ, которым Android раздувает XML-файлы макета и по-прежнему извлекает выгоду из оптимизаций и преимуществ XML, которые Android имеет как скомпилированные XML-файлы, так и ссылки на произвольные ресурсы в ваших пользовательских XML-файлах. Вы не можете напрямую подключиться к существующему LayoutInflater потому что этот класс может иметь дело только с раздутием View s. Чтобы нижеследующий код работал, поместите ваш 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; } } 

Выше я ссылаюсь на атрибуты через строковое представление. Если вы хотите пойти дальше, вы можете определить ресурсы атрибутов для конкретных приложений и использовать их вместо этого, но это будет усложнять ситуацию совсем немного (см. Объявление пользовательского элемента пользовательского интерфейса Android с использованием 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 

Обратите внимание: вы не можете иметь @resource/scout в вашем XML-файле, поскольку resource не является допустимым типом ресурса, но @string/foo работает нормально. Вы также можете использовать, например, @drawable/foo с некоторыми незначительными модификациями кода.

Если вы расширите существующий класс представления, например TextView, EditText, вы можете вызвать его внутри макета xml.

Это Android-ссылка для настраиваемого компонента.

И вы можете также определить пользовательские xml attrubutes, это пример и еще один .

Надеюсь, это поможет вам!

Механизм сериализации XML несовместим с Android. Я бы порекомендовал Json, возможно, с библиотекой Gson.