En éste artículo vamos a desarrollar un lector de RSS muy simple para Android utilizando Appcelerator Titanium.
El primer paso es la creación de un nuevo proyecto móvil usando Titanium Studio (puedes consultar el post creación de una aplicación para Android con Appcelerator Titanium)
Una vez creado el proyecto, vamos a definir la estructura de directorios. Se podría empezar a poner el código de la primera ventana directamente en app.js pero para que quede todo más organizado y sea más fácil de mantener, podemos crear una carpeta “windows” donde pondremos todas las ventanas y app.js llamará a la primera ventana para empezar.
Siguiendo ésta idea, creamos un nuevo fichero .js para la primera ventana dentro de la carpeta “windows”.
Seguidamente, tenemos que editar app.js para que en ejecutar la aplicación llame a la primera ventana. Suponiendo que la ventana está definida en el fichero list.js, el código seria el siguiente:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
var list = Titanium.UI.createWindow({
id:"rss",
title: "Últimos feeds",
url: 'windows/list.js'
});
list.open({
modal:true
});
Cuando utilizamos un nuevo fichero .js, tenemos que obtener la referencia a la “ventana” de la aplicación. Debemos tener presente que cuando creamos una ventana a partir de un fichero .js diferente, todas las variables y funciones definidas en los otros ficheros no están disponibles. A priori, sólo tenemos acceso a las funciones de Titanium.
Para obtener la referencia a la ventana actual:
1
var w = Titanium.UI.currentWindow;
A partir de aquí, ya podemos crear nuevos controles de Titanium y añadirlos.
Aunque podríamos mezclar todo el código necesario en el mismo fichero (código para montar la pantalla y código para obtener el RSS), en éste caso vamos a crear otro fichero con las funciones necesarias para conectarse al feed y obtener los datos. Para hacerlo, creamos otro directorio que le podemos llamar “data” y éste nuevo fichero que le llamamos “Reader.js”. La estructura de directorios queda como sigue:
Ahora que ya tenemos la estructura, ya podemos empezar a escribir el código. Vamos primero por el fichero Reader.js (el encargado de conectarse a la url indicada y obtener la información del feed):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
function Reader(url, callback) {
var xhr = Ti.Network.createHTTPClient();
xhr.open("GET",url);
Reader.getValue = function(xmlElement) {
if (xmlElement && xmlElement.length>0) {
return xmlElement.item(0).text;
}
return null;
}
xhr.onload = function() {
try {
// Variable donde guardar los resultados
var result = new Object();
result.entries = new Array();
var doc = this.responseXML.documentElement;
var items = doc.getElementsByTagName("item");
result.title = doc.evaluate("//channel/title/text()").item(0).nodeValue;
for (var c=0;c<items.length;c++) {
var entry = new Object();
var item = items.item(c);
entry.title = Reader.getValue(item.getElementsByTagName("title"));
entry.description = Reader.getValue(item.getElementsByTagName("description"));
entry.pubDate = Reader.getValue(item.getElementsByTagName("pubDate"));
entry.url = Reader.getValue(item.getElementsByTagName("link"));
entry.media = Reader.getValue(item.getElementsByTagName("media:thumbnail"));
result.entries[c]=entry;
}
callback(result);
} catch(E) {
alert(E);
}
};
xhr.send();
}
Como podéis ver, ésta función utiliza la clase de Titanium Ti.Network.createHTTPClient() para hacer una petición GET a la url del rss. Al recibir la respuesta, se llama al callback definido para el evento onload que será el encargado de parsear el XML obtenido y generar un nuevo objeto javascript. Una vez ha terminado, llama a la función que se ha pasado como parámetro pasándole el resultado.
La idea es que la vista llamará a la función Reader pasándole la url del feed y la función que tratará los resultados al recibirlos. La llamada http es asíncrona.
Ahora podemos pasar al código de la ventana en sí. Es el siguiente:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
Titanium.include('/data/Reader.js');
var w = Titanium.UI.currentWindow;
var scrollView = Titanium.UI.createScrollView({
showVerticalScrollIndicator:true
});
scrollView.add(tableView = Titanium.UI.createTableView({
height: 400
}));
var tableview = Titanium.UI.createTableView();
w.add(tableview);
// Añadimos el handler de click en la tabla
tableview.addEventListener('click', function(e) {
var detail = Ti.UI.createWindow({
title:e.row.hTitle
});
var wb = Ti.UI.createWebView({
url:e.row.url
});
detail.add(wb);
detail.open({modal:true});
});
// Menú de opciones
var activity = Ti.Android.currentActivity;
activity.onCreateOptionsMenu = function(e) {
var menu = e.menu;
var menuItem = menu.add({ title: "Recargar"});
menuItem.addEventListener('click', function() {
loadRss();
});
}
// Variable para guardar los datos que se mostrarán en la vista
var data;
// Cargamos los RSS
loadRss();
function loadRss() {
data = new Array();
new Reader("http://www.3cat24.cat/rss/not_notportada_rss.xml", printRssStream);
new Reader("http://www.agilogy.com/rss", printRssStream);
}
// Rellena la variable data con los datos del rss
function printRssStream(result) {
for (var i=0; i<result.entries.length; i++) {
var entry = result.entries[i];
var row = Titanium.UI.createTableViewRow();
if (i==0) {
// Si es la primera celda, le ponemos la cabecera
row.header=result.title;
}
if (entry.media!=null) {
var img = Ti.UI.createImageView({
image: entry.media,
left:5,
height:60,
width:60
});
row.add(img);
var label = Ti.UI.createLabel({
text: entry.title,
left:72,
top:5,
bottom:5,
right:5
});
row.add(label);
} else {
var label = Ti.UI.createLabel({
text: entry.title,
left:5,
top:5,
bottom:5,
right:5
});
row.add(label);
}
row.url = entry.url;
row.hTitle = entry.title;
data[data.length] = row;
}
tableview.setData(data);
}
A destacar de éste código:
- Empezamos incluyendo el fichero "Reader.js" para poder acceder al código que hemos definido anteriormente
- Se obtiene la ventana de la aplicación y a partir de ahí, se van añadiendo los controles
- Hacemos las llamadas al Reader con las diferentes urls de los RSS que nos interesan. En cada llamada, le pasamos la función que utilizaremos de callback (printRssStream) para el resultado
- printRssStream obtiene el resultado y añade las filas necesarias a la tabla
- Se ha añadido un event listener a la tableView para responder a los clicks del usuario. Si se selecciona una fila, se abrirá una nueva webView que mostrará el contenido del link de la entrada del rss correspondiente. Una webView es una vista para abrir contenido local o remoto en HTML5
- Se añade un menú con la opción de recargar el RSS. Los menús se crean en el momento en que son necesarios por lo que su creación está ligada a recibir el evento onCreateMenuOptions de la activity actual. Las activities tienen más eventos relacionados con los menús. Por ejemplo, si se quieren precargar.
La función printRssStream en lugar de utilizar una variable global “data” e irle añadiendo las filas, podría añadirlas una a una directamente a la tabla utilizando tableview.addRow(row). Sin embargo, es más eficiente pasarle al tableView todas las filas de golpe que ir añadiéndolas de una en una (teniendo en cuenta que nosotros las obtenemos ya todas de golpe).
Si ejecutamos la aplicación en el emulador: