Din cei in ce mai multe dispozitive mobile sunt folosite pentru a accesa serviciile Internet pri conexiuni de date. O modalitate eficienta de a transfera date intre platforme si tehnologii diferite este de a utiliza fisiere XML, care sunt simple fisiere text formatate conform regulilor XML.
Pentru a procesa un fisier XML si pentru a extrage datele necesare este nevoie de un parser XML, care implementeaza un motor pentru procesare de texte.
Problema in cazul aplicatiilor MIDlet J2ME este ca exista dispozitive mobile care nu suporta API-ul XML pentru Java ME degfinit de pachetul suplimentar ( JSR 280 ). Pentru a rezolva aceasta problema, avem nevoie de un parser XML simplu si independente, care trebuie sa fie rapid si cu un impact mic asupra memoriei (in special cea virtuala). Doua solutii posibile sunt kXML si NanoXML .
In urmatorul exemplu de MIDlet (Aveti posibilitatea de a descarca codul sursa complet, inclusiv o aplicatie MIDlet completa ), vom folosi kXML pentru a analiza un feed RSS furnizat de acest site: itcsolutions.eu feed RSS .
Cum se foloseste kXML
Pentru a intelege cum:
- se instaleaza kXML intr-un proiect J2ME dezvoltat in NetBeans;
- se folosesc metode din clasa org.kxml2.io.KXmlParser ;
cititi articolul Cum sa folosesti kXML pentru a parsa fisiere XML in aplicatii J2ME post.
Cum se acceseaza un XML pe Web dintr-un MIDlet
Pentru a accesa un document XML de pe Web, avem nevoie de un obiect HttpConnection. Dupa ce vom obtine o conexiune activa, putem procesa XML-ul la nivel de caracter (ca fisier text) sau la nivel de octet.
Pentru procesarea XML-ul la nivel de caracter, avem nevoie de un InputStreamReader (acesta va fi creat pe baza obiectului InputStream generat de conexiune). Acest lucru va fi argument de intrare pentru crearea instantei de parser kXML.
Deoarece procesele care au nevoie de acces la retea pot bloca executia firului principal, intreaga procedura de obtinere a fisierului XML pe baza unui URL dat si parsarea acestuia va fi executata intr-un fir secundar. Acest lucru va impiedica blocarea aplicatiei si va permite utilizatorilor sa foloseasca comenzile, cum ar fi comanda Exit care inchide aplicatia. Altfel, firul principal va astepta terminarea operatiei ce foloseste reteaua (realizare conexiune, descarcare fisier, etc.) pentru a permite executia comenzilor.
Metoda care gestioneaza conexiunea HTTPin vederea descarcarii documentului XML este getXMLFeed():
public void getXMLFeed(final String url) {
Thread t = new Thread() {
public void run() {
HttpConnection myConnection = null;
try {
//open the connection
myConnection = (HttpConnection) Connector.open(url);
//get the bytes stream
InputStream stream = myConnection.openInputStream();
//call the parsing method
ParseXMLFeed(stream);
} catch (Exception error) {
parentMidlet.DisplayError(error);
} finally {
//close the connection
try {
if (myConnection != null) {
myConnection.close();
}
} catch (IOException eroareInchidere) {
//calls a method from the MIDlet that display an alert
parentMidlet.DisplayError(eroareInchidere);
}
}
}
};
//starts the thread
t.start();
}
Cum se parseaza feed-ul RSS folosind kXML
Pentru a putea utiliza parser-ul kXML trebuie:
- sa se cunoasca structura documentului XML; in acest exemplu, XML-ul este itcsolutions.eu RSS feed ;
- cunoscute metodele clasei kXML:Cum sa folosesti kXML pentru a parsa fisiere XML in aplicatii J2ME;
Metoda din MIDlet care implementeaza procedura de parsare a XML-ului este ParseXMLFeed():
- argumentul metodei este o referinta InputStream; aceasta va fi utilizata pentru a crea o referinta Reader necesarea prelucrarii XML-ului la nivel de char si, de asemenea, necesara pentru definirea argumentului de intrare pentru constructorul clasei kXmlParser;
- metoda extage titlul si link-ul pentru fiecare element RSS; datele sunt stocate intr-un (clasa definita in pachetul utility) obiect de tip News; elementul News este adaugat intr-un vector definite la nivelul MIDlet-ului folosind metoda addNews();
Pasi care definesc procesul de analiza a feed-ului XML sunt:
- se creaza si se se initializeaza o instanta de tip KXmlParser folosind ca argument un InputStreamReader furnizat de HttpConnection ;
- deoarece nodurile <item> sunt sub-noduri pentru<channel> si vrem sa le prelucram intr-un mod iterativ, trebuie sa sarim peste nodul <rss> in mod explicit;
- iterarea prin colectia de noduri se face prin metoda nextTag() si pentru fiecare eticheta de start <item> extragem titlul si link-ul; aceste informatii, titlul si link-ul, sunt folosite pentru a crea un obiect News, care se adauga la colectia de tip Vector a MIDlet-ului;
- pentru orice nod, altul decât <item>, sarim peste el si detaliile sale folosind metoda skipSubTree();
- atunci când vom ajunge la o eticheta <channel>, inseamna ca am terminat sub-arborele sau acesta fiind tag-ul final;
private void ParseXMLFeed(InputStream input)
throws IOException, XmlPullParserException {
Reader dataReader = new InputStreamReader(input);
//kXML parser
KXmlParser myParser = new KXmlParser();
myParser.setInput(dataReader);
//skip the first node - rss
myParser.nextTag();
myParser.require(XmlPullParser.START_TAG, null, "rss");
//skip the second node - channel
myParser.nextTag();
myParser.require(XmlPullParser.START_TAG, null, "channel");
myParser.nextTag();
myParser.require(XmlPullParser.START_TAG, null, "title");
while (myParser.getEventType() != XmlPullParser.END_DOCUMENT) {
String name = myParser.getName();
//this is for reaching the end tag for channel node
if (name.equals("channel")) {
break;
}
//this is for each item node in the RSS feed
if (name.equals("item")) {
//process it only if it is reached the start tag
if (myParser.getEventType() != XmlPullParser.END_TAG) {
myParser.nextTag();
String title = myParser.nextText();
myParser.nextTag();
String link = myParser.nextText();
//create a new News item
News news = new News(title, link);
parentMidlet.addNews(news);
}
} else {
//if it is not the item node the skip it and all its details
myParser.skipSubTree();
}
//move to the next tag
myParser.nextTag();
}
//close the input stream - job done
input.close();
}
Cum este implementata solutia in aplicatia mobila
- aplicatia gestioneaza elementele feed-ului RSS (doar titlul si link-ul) folosind o colectie de obiecte Vector Stiri, news;
- titlul fiecarui obiect News este afisat intr-un formular tip List, myNewsList ;
- pentru a adauga elemente la colectia Vector, MIDlet-ul ofera o metoda publica addNews(); de asemenea, metoda reincarca formularul tip List, myNewsList, pe Display generand astfel o actualizare a datelor afisate;
//method called by the parsing thread
public void addNews(News newsItem){
news.addElement(newsItem);
myNewsList.append(newsItem.getTitle(),null);
myDysplay.setCurrent(myNewsList);
}
- aplicatia are 2 comenzi: una pentru inchiderea aplicatiei, cmdExit, si una, cmdDetails, pentru afisa intr-un Alert detalii (link-ul) pentru titlul selectat in lista;
public void commandAction(Command command, Displayable displayable) {
if(command == cmdExit){
destroyApp(false);
notifyDestroyed();
} else
if(command == cmdDetails || command == List.SELECT_COMMAND){
//get the index of the selected title
int index = myNewsList.getSelectedIndex();
if(index!=-1) {
//get the Vector element at that index - News object
News newsItem = (News)news.elementAt(index);
//display the link in an Alert
Alert message = new Alert(newsItem.getTitle(),
newsItem.getLink(),
null,
null);
message.setTimeout(Alert.FOREVER);
myDysplay.setCurrent(message,myNewsList);
} else
return;
}
}
- MIDlet-ul are 2 fire de executie, cel principal, care este folosit pentru a afisa formularul List si pentru a gestiona cele 2 comenzi; al doilea fir implementeaza procesul de parsare; al doilea fir de executie incepe atunci când metoda getXMLFeed() este apelata (acesta defineste o clasa interna derivata din Thread pentru a gestiona un fir de executie separat);
public void startApp() {
myNewsList.setCommandListener(this);
//the XML file url
String url = "http://www.itcsolutions.eu/feed/";
ParseThread myThread = new ParseThread(this);
//this will start the second thread
myThread.getXMLFeed(url);
Display.getDisplay(this).setCurrent(myNewsList);
}
Cele 2 interfete principale ale aplicatiei sunt:
Aveti posibilitatea de a descarca codul sursa complet, inclusiv o aplicatie MIDlet completa.