2011-12-04 26 views
7

C'è un modo per creare un tipo di dati XML personalizzato per Android?Creare un tipo di dati XML personalizzato?

ho una classe Model che contiene tutte le statistiche dei miei soggetti. Voglio essere in grado di gonfiare la classe Model da xml simili - beh, esattamente come fanno le View. È possibile?

Esempio:

<?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> 

E la classe vorrei gonfiare.

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

risposta

8

Con un codice personalizzato che utilizza API accuratamente selezionate, è possibile imitare il modo in cui Android gonfia i file XML di layout e ancora beneficiare delle ottimizzazioni XML e dei gadget che Android ha come file XML compilati e riferimenti a risorse arbitrarie all'interno dei file XML personalizzati. Non è possibile connettersi direttamente allo LayoutInflater esistente poiché questa classe può gestire solo il gonfiaggio di View s. Affinché il codice sottostante funzioni, inserisci il tuo file XML in "res/xml" nella tua applicazione.

In primo luogo, ecco il codice che analizza il file (compilato) XML e invoca il costruttore Model. Potresti voler aggiungere un meccanismo di registrazione in modo da poter facilmente registrare una classe per qualsiasi tag, oppure potresti voler usare ClassLoader.loadClass() in modo che tu possa caricare le classi in base al loro nome.

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

Con questo in luogo, si può mettere il "parsing" degli attributi all'interno della classe Model, molto simile View lo fa:

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

Sopra ho fatto riferimento attributi attraverso la rappresentazione di stringa. Se si desidera andare oltre, è possibile definire risorse di attributo specifiche dell'applicazione e utilizzarle, ma ciò complicherà un po 'le cose (vedere Declaring a custom android UI element using XML). In ogni caso, con tutta la messa a punto delle risorse e questo in un'attività fittizia:

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

si otterrà questa uscita:

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 

Si noti che non si può avere @resource/scout nel file XML poiché non è resource un tipo di risorsa valido, ma @string/foo funziona correttamente. Dovresti anche essere in grado di usare ad esempio @drawable/foo con alcune piccole modifiche al codice.

+0

Grazie signore per la risposta molto dettagliata; tu sei il mio eroe. – AedonEtLIRA

0

Il meccanismo di serializzazione XML non è coerente su Android. Consiglierei invece Json, possibilmente con la libreria Gson.

1

se si estende una classe vista esistente per esempio TextView, EditText, si può chiamare all'interno del layout xml.

Questa è la Android Reference per componente personalizzato.

E si possono definire anche gli attributi personalizzati xml, questo è uno example e uno another one.

Spero che aiuta per voi!

+0

Grazie per l'input, ma non sto estendendo Visualizza o qualsiasi altro widget.Voglio avere un file xml raw che punta alle risorse che ho definito nella mia stringa e nei file xml interi [R]. – AedonEtLIRA

Problemi correlati