Está en la página 1de 20

Aumentar la

funcionalidad de un
lector de feeds
!
captulo
!9 !"#$% '()#%*)
0(1+,*'" 3
Aumentar la funcionalidad de un lector de feeds
Ll lecLor de feed que desarrollaremos en esLe caplLulo se dlferencla del anLerlor porque permluremos
al usuarlo decldlr sl al preslonar sobre un elemenLo qulere verlo en una vlsLa prevla denLro de la apll-
cacln o en el navegador, para esLa eleccln agregaremos un menu y personallzaremos el vlew de cada
la del resulLado.
Ll e[emplo se ver de la slgulenLe manera:
Disposicin inicial
Lmpecemos #)/5,$6,"#% )* 57#&6%
1
que debe ser lmporLado hacla un nuevo proyecLo es muy slmllar
al del caplLulo anLerlor, pero revlsemos las dlferenclas:

Ll xMLarser ahora obuene no solo el llnk y uLulo de cada aruculo, Lamblen su auLor, fecha, descrlp-
) hups://glLhub.com/androldMuW/gula2base
!@ !"#$% '()#%*)
cln y una lmagen.

ara ser ms ordenados, la lnformacln se guardar uullzando una clase de !ava que represenLe a
cada aruculo llamada LlemenL (src/com/androld/mdw/demo/LlemenL.[ava)

La Activity prlnclpal (Maln) hereda de ListActivity y no de Activity faclllLando y
permlLe camlnos corLos para cosas especlcas a una AcuvlLy que muesLra un llsLado de cosas. or
lo mlsmo, en el layouL es necesarlo un LlsLvlew con el ldenucador @android:id/list
Adems, uene las especlcaclones de la gula anLerlor.

Ls necesarlo darle permlso a la apllcacln para que pueda accesar a lnLerneL, Lener un Llnear-
LayouL con orlenLacln verucal en el archlvo de dlseno prlnclpal por Lraba[ar con una LlsAcuvlLy
Lamblen neceslLamos el LlsLvlew con ld @android:id/list y Lener una forma de reconocer
xML.
Diseo
1raba[amos con vlews del caplLulo anLerlor como: LlnearLayouL, LlsLvlew, 1exLvlew, 8uuon y agregamos
nuevas vlews.

0@,6)1&)2
1
: muesLra una lmagen que puede cargarse de dlferenLes fuenLes para el e[emplo
vamos a obLenerla de una dlreccln de lnLerneL (euqueLa lmg de P1ML denLro del aruculo) revlsar
(2d Craphlcs
2
).

3)".
3
y 3)".0-)@
4
: en esLe caplLulo aprenders cmo hacer un menu de opclones en xML, revl-
sar (3)"./
5
).
ara el layouL prlnclpal, repeumos el procedlmlenLo del caplLulo anLerlor de nuevo recordando que el
ldenucador (android:id) del LlsLvlew debe ser @android:id/list.
Adems, neceslLaremos 3 vlews adlclonales:
) hup://developer.androld.com/reference/androld/wldgeL/lmagevlew.hLml
. hup://developer.androld.com/gulde/Loplcs/graphlcs/2d-graphlcs.hLml
3 hup://developer.androld.com/reference/androld/vlew/Menu.hLml
@ hup://developer.androld.com/reference/androld/vlew/MenulLem.hLml
3 hup://developer.androld.com/gulde/Loplcs/ul/menus.hLml
!; !"#$% '()#%*)

ara el menu menu.xml

ara la vlsLa prevla denLro de la apllcacln showelemenL.xml

ara cada la del llsLado row.xml
ara agregar esLos vlews, hacemos cllck derecho sobre la carpeLa /res/layouL luego new > (nuevo) y
oLher. (oLro):
Ln el dllogo que aparece selecclonamos archlvo xML de Androld y hacemos cllck en nexL > (slgulenLe):
!< !"#$% '()#%*)
Lscrlblmos el nombre del archlvo (es lmporLanLe lnclulr la exLensln xML), en el e[emplo el nombre es
menu.xml y hacemos cllck en el boLn llnlsh (nallzar):
LsLe procedlmlenLo es necesarlo cada vez que neceslLemos un LayouL nuevo, para esLa apllcacln sern
necesarlos 3: menu.xml, row.xml y showelemenL.xml descrlblremos a deLalle cada uno de ellos.
View para el men: menu.xml
uullza un elemenLo menu y dos elemenLos lLem para cada opcln, le pondremos a cada lLem LexLo y el
lcono que Lrae por defecLo la apllcacln, el archlvo xML debe quedar asl:
<!--?xml version=1.0 encoding=utf-8?-->
Ll menu deberla verse de la slgulenLe forma:
!= !"#$% '()#%*)
View para preview: showelement.xml
Ln esLa vlsLa prevla mosLraremos el uLulo del aruculo, el auLor y la descrlpcln, neceslLamos varlos 1exL-
vlew denLro de un LlnearLayouL con orlenLacln verucal, el archlvo xML debe quedar asl:
<!--?xml version=1.0 encoding=utf-8?-->
La vlsLa prevla deberla verse de la slgulenLe forma:
!> !"#$% '()#%*)
View para la: row.xml
Ln esLe caplLulo en cada una de las las de la llsLa no mosLraremos dos llneas como en el anLerlor, ahora
vamos a Lener una lmagen del elemenLo y su uLulo agrupados por un LlnearLayouL con orlenLacln horl-
zonLal, el archlvo xML debe quedar de la slgulenLe forma:
<!--?xml version=1.0 encoding=utf-8?-->
Clases de apoyo
Ln esLa versln del lecLor de feeds Lenemos varlas clases que apoyan para faclllLar el desarrollo:

E*)@)"-: guarda los daLos de cada aruculo en el llsLado.

3:!LL: clase de apllcacln para represenLar daLos volules denLro de la apllcacln.

3:!#,L-)$: adapLador personallzado que permlLe mosLrar la lmagen en cada la del llsLado.
ara la vlsLa prevla del aruculo neceslLamos oLra AcuvlLy que es oLra clase que llamaremos ShowLle-
menL.[ava para agregar una clase es necesarlo hacer cllck derecho sobre com.androld.mdw.demo (ba[o
src) luego new (nuevo) y por ulumo Class (clase).
uespues colocamos el nombre MyApp" para el e[emplo y la superclase (clase de la que hereda) androld.
6? !"#$% '()#%*)
app.Appllcauon para el e[emplo y hacemos cllck en nallzar.
Ll proceso es necesarlo para MyApp, MyAdapLer y ShowLlemenL la clase LlemenL va lnclulda, ahora
1">9-$ "2 6-'8"'%:- :" 6>:> ,'> :" "$8>$ 62>$"$3
Element
Paremos un ob[eLo LlemenL, para aumenLar el orden porque ahora guardaremos ms lnformacln de
cada elemenLo del llsLado obLenldo del feed. LsLa clase esL lnclulda en los archlvos de prueba y no es
muy compllcada, mane[a meLodos para colocar y obLener los aLrlbuLos de cada elemenLo como: 1lLulo,
Lnlace, AuLor, uescrlpcln, lecha de publlcacln, lmagen.
SeLlmage es el meLodo dlferenLe y se debe a la forma en que obLenemos las lmgenes. Ll parser xML
buscar denLro del conLenldo del aruculo la prlmera ocurrencla de la euqueLa lmg de P1ML y en algu-
nos casos la unlca es la foLo del auLor del aruculo.
6: !"#$% '()#%*)
1omamos presLada la lmagen del avaLar de 1wluer de O@,)/-$%/
1
el u8L es:
hup://a1.Lwlmg.com/prole_lmages/82883809/mdw_hr_reasonably_small.png
La u8L se reclbe como parmeLro en esLe meLodo, sl al LraLar de obLener la lmagen algo fallara enLonces
Lamblen se esLablece la lmagen del avaLar de 1wluer. ara obLener la lmagen en base a un u8L se uullza
la ayuda de la funcln loadlromurl que devuelve un J&-@,L
2
.
LsLe meLodo abre una conexln hacla el u8L especlcado, luego decodlca el u[o (sLream) de byLes
reclbldo y en base a ellos consLruye un ob[eLo 8lLmap. Ll cdlgo de la clase LlemenL (ya lncluldo en el
cdlgo base de la gula) es el slgulenLe:
package com.android.mdw.demo;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.SimpleDateFormat;
import java.util.Date;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
public class Element {
static SimpleDateFormat FORMATTER = new SimpleDateFormat(EEE, dd MMM yyyy
HH:mm:ss Z);
private String title;
private String author;
private String link;
private Bitmap image;
private String description;
private Date date;
public String getTitle() {
return this.title;
) hup://Lwluer.com/maesLros
. hup://developer.androld.com/reference/androld/graphlcs/8lLmap.hLml
6! !"#$% '()#%*)
}
public String getLink() {
return this.link;
}
public String getDescription() {
return this.description;
}
public String getDate() {
return FORMATTER.format(this.date);
}
public Bitmap getImage(){
return this.image;
}
public String getAuthor(){
return this.author;
}
public void setTitle(String title) {
this.title = title.trim();
}
public void setLink(String link) {
this.link = link;
}
public void setDescription(String description)
{ this.description = description.trim();
}
public void setDate(String date) {
try {
this.date = FORMATTER.parse(date);
} catch (java.text.ParseException e) {
e.printStackTrace();
}
}
public void setImage(String image)
{ if (image.contains(autor)) {
image = http://a1.twimg.com/prohle_images/82885809
66 !"#$% '()#%*)
/mdw_hr_reasonably_small.png;
}
try {
this.image = loadFromUrl(new URL(image));
} catch (Exception e) {
try {
this.image = loadFromUrl(new URL(http://a1.twimg.com
/prohle_images/82885809/mdw_hr_reasonably_small.png));
} catch (MalformedURLException e1) {}
}
}
public void setAuthor(String author){
this.author = author;
}
public String toString(){
return this.title;
}
private Bitmap loadFromUrl(URL link) {
Bitmap bitmap = null;
InputStream in = null;
try {
in = link.openConnection().getInputStream();
bitmap = BitmapFactory.decodeStream(in, null, null);
in.close();
} catch (IOException e) {}
return bitmap;
}
}
MyApp
Ln el caplLulo anLerlor el llsLado de aruculo los represenLamos como una llsLa esLuca denLro de la clase
de la acuvlLy prlnclpal, menclone que esa no era la forma correcLa por que deblan uullzarse clases de
apllcacln y para eso uullzaremos MyApp.
69 !"#$% '()#%*)
no es poslble uullzar una varlable local o una varlable de lnsLancla porque la Acnv|ty
1
"$ 6-'$8>'8"-
menLe desLrulda y creada de nuevo. or e[emplo, al roLar el Lelefono. A pesar de esLar represenLado
denLro de una clase esLa lnformacln no de[a de ser volul, para almacenamlenLo permanenLe es nece-
sarlo una base de daLos de SCLlLe.
ara declrle a la apllcacln que es de upo MyApp es necesarlo edlLar el manlfesL AndroldManlfesL.xml y
en los aLrlbuLos de la euqueLa apllcacln agregar androld:name="MyApp"
7'%6%>29"'8" :"6?>3
<application android:icon=@drawable/icon android:label=@string/app_name>
Al modlcarlo debe declr:
<application android:icon=@drawable/icon android:label=@string/app_name
android:name=MyApp>
uenLro de la clase MyApp vamos a guardar dos cosas:

Ll llsLado de los aruculos

La opcln selecclonada por el usuarlo para vlsuallzar el aruculo (ya sea en una vlsLa prevla denLro
de la apllcacln o en el navegador)

Adems de esLas dos varlables de lnsLancla, vamos a lnclulr meLodos para guardar y devolver esLas
varlables (geuers y seuers). ara represenLar la opcln eleglda por el usuarlo uullzaremos enLeros
denLro de la AcuvlLy prlnclpal, esLos esLn lncluldos en el cdlgo base y fueron denldos asl:
hnal static int APP_VIEW = 1;
hnal static int BROWSER_VIEW = 2;
Al lnlclar la apllcacln, colocaremos el valor de A_vlLW en el campo que guarda la preferencla del
usuarlo denLro de la clase de apllcacln, el cdlgo de la clase MyApp queda de la slgulenLe forma:
package com.android.mdw.demo;
import java.util.LinkedList;
) hup://developer.androld.com/reference/androld/app/AcuvlLy.hLml
6@ !"#$% '()#%*)
import android.app.Application;
public class MyApp extends Application {
private LinkedList data = null;
private int selectedOption = Main.APP_VIEW;
public LinkedList getData(){
return this.data;
}
public void setData(LinkedList d){
this.data = d;
}
public int getSelectedOption(){
return this.selectedOption;
}
public void setSelectedOption(int selectedOption)
{ this.selectedOption = selectedOption;
}
}
MyAdapter
La clase MyAdapLer ser una personallzacln de un !$$,:!#,L-)$
1
, un adapLador que reclbe un arre-
glo (o llsLado) de elemenLos. La clase MyAdapLer hereda de ArrayAdapLer<LlemenL>, denLro de la clase
mane[aremos dos varlables de lnsLancla, un LayoutInater
2
esLa clase se uullzar para lnsLanclar el
dlseno a parur de un archlvo de xML hacla un vlew y adems un llsLado (LlnkedLlsL) de ob[eLos (en esLe
caso, aruculos, represenLados por la clase LlemenL).
uenLro del consLrucLor, llamamos al padre (super) y aslgnamos a los campos (varlables de lnsLancla).
Adems, dado que queremos personallzar la represenLacln (renderlng) de cada la, neceslLamos
sobrecargar revlsar (Cverr|de
3
) el meLodo geLvlew.
uenLro de esLe meLodo, cuando sea necesarlo lnsLanclamos el archlvo de su dlseno correspondlenLe
row.xml y le aslgnamos valor a sus vlews (lmagen y LexLo) a parur de la lnformacln guardada en el
) hup://developer.androld.com/reference/androld/wldgeL/ArrayAdapLer.hLml
. hup://developer.androld.com/reference/androld/vlew/LayouLlnaLer.hLml
3 hup://download.oracle.com/[avase/LuLorlal/[ava/landl/overrlde.hLml
6; !"#$% '()#%*)
llsLado de aruculos.
Ll cdlgo de la clase MyAdapLer es el slgulenLe:
package com.android.mdw.demo;
import java.util.LinkedList;
import android.content.Context;
import android.view.LayoutInHater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
public class MyAdapter extends ArrayAdapter {
LayoutInHater inf;
LinkedList objects;
public MyAdapter(Context context, int resource,
int textViewResourceId,
LinkedList objects) {
super(context, resource, textViewResourceId, objects);
this.inf = LayoutInHater.from(context);
this.objects = objects;
}
public View getView(int position, View convertView,
ViewGroup parent){
View row = convertView;
Element currentElement = (Element)objects.get(position);
if (row == null) {
row = inf.inHate(R.layout.row, null);
}
ImageView iv = (ImageView) row.hndViewById(R.id.imgElement);
iv.setImageBitmap(currentElement.getImage());
iv.setScaleType(ImageView.ScaleType.FIT_XY);
TextView tv = (TextView) row.hndViewById(R.id.txtElement);
6< !"#$% '()#%*)
tv.setText(currentElement.getTitle());
return row;
}
}
ShowElement
or ulumo Lenemos la AcuvlLy que nos mosLrar la vlsLa prevla del aruculo selecclonado, cada vez que
se agrega un AcuvlLy es necesarlo especlcarlo en el manlfesL AndroldManlfesL.xml, ba[o la euqueLa de
apllcacln (<appllcauon>) vamos a colocar:
<activity android:name=.ShowElement></activity>
ara pasar la lnformacln enLre las Acuvlues uullzaremos la lnformacln exLra puede llevar un &"-)"-
1

prevlo a levanLar una AcuvlLy. ulsponemos de un dlcclonarlo que en nuesLro caso uullzaremos para
mandar un enLero represenLando la poslcln del elemenLo que queremos vlsuallzar.
ara empezar obLenemos el lnLenL que levanLo esLa acuvlLy que deberla Lraer la poslcln del elemenLo
a vlsuallzar, sl en caso fuera nulo (el lnLenL que levanLo esLa apllcacln no manda nada) enLonces se le
aslgna el valor por defecLo (esperamos que la poslcln sea mayor o lgual que 0, enLonces para dlsungulr
un error podemos aslgnar -1).
Intent it = getIntent();
int position = it.getIntExtra(Main.POSITION_KEY, -1);
Con la poslcln reclblda, buscamos a Lraves de la clase de apllcacln MyApp y llamando al meLodo
geLuaLa obLenemos el aruculo que nos lnLeresa:
MyApp appState = ((MyApp)getApplication());
Element e = appState.getData().get(position);
Luego colocamos esos valores en los campos correspondlenLes denldos en su dlseno showelemenL.
xml sl en caso no se reclblera una poslcln vllda, se regresa a la AcuvlLy prlnclpal envlando la poslcln
-1 para lndlcar que hubo un error:
Intent backToMainActivity = new Intent(this, Main.class);
backToMainActivity.putExtra(Main.POSITION_KEY, -1);
) hup://developer.androld.com/reference/androld/conLenL/lnLenL.hLml#geLlnLLxLra28[ava.lang.SLrlng,20lnL29
6= !"#$% '()#%*)
startActivity(backToMainActivity);
Al nallzar, el cdlgo de esLa clase es el slgulenLe:
package com.android.mdw.demo;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.widget.TextView;
public class ShowElement extends Activity {
@Override
public void onCreate(Bundle savedInstanceState)
{ super.onCreate(savedInstanceState);
setContentView(R.layout.showelement);
Intent it = getIntent();
int position = it.getIntExtra(Main.POSITION_KEY, -1);
if (position != -1) {
MyApp appState = ((MyApp)getApplication());
Element e = appState.getData().get(position);
TextView txtTitle = (TextView)hndViewById(R.id.txtTitle);
txtTitle.setText(e.getTitle());
TextView txtAuthor = (TextView)hndViewById(R.id.txtAuthor);
txtAuthor.setText(por + e.getAuthor());
TextView txtDesc = (TextView)hndViewById(R.id.txtDesc);
txtDesc.setText(e.getDescription());
} else {
Intent backToMainActivity = new Intent(this, Main.class);
backToMainActivity.putExtra(Main.POSITION_KEY, -1);
startActivity(backToMainActivity);
}
}
}
Lsas son las clases adlclonales luego el Lraba[o es sobre la AcuvlLy prlnclpal: la clase Maln.[ava
6> !"#$% '()#%*)
Mostrar datos siguiendo el diseo
La funcln auxlllar seLuaLa de la gula anLerlor se ve drsucamenLe reduclda ya que ahora uullzamos
nuesLro adapLador y por Lener una acuvlLy que hereda de LlsLAcuvlLy la aslgnacln al LlsLvlew lo hace-
mos con seLLlsLAdapLer.
private void setData(){
this.setListAdapter(new MyAdapter(this, R.layout.row, 0,
appState.getData()));
}
LsLa herencla de nuesLra AcuvlLy, Lamblen nos permlLe colocar la funcln onLlsLlLemCllck para especl-
car la operacln a reallzar cuando el usuarlo preslona cllck sobre un elemenLo. valldamos la opcln
selecclonada por el usuarlo guardada en la clase de apllcacln y dependlendo del caso levanLamos un
lnLenL dlferenLe.
protected void onListItemClick(ListView l, View v, int position, long id)
{ super.onListItemClick(l, v, position, id);
Intent nextActivity = null;
if (appState.getSelectedOption() == APP_VIEW) {
nextActivity = new Intent(this, ShowElement.class);
nextActivity.putExtra(POSITION_KEY, position);
} else {
LinkedList data = appState.getData();
nextActivity = new Intent(Intent.ACTION_VIEW,
Uri.parse(data.get(position).getLink()));
}
this.startActivity(nextActivity);
}
ermanece la varlable de lnsLancla para el dllogo de progreso y el mane[ador es llgeramenLe dlsunLo
porque ya no reclbe los daLos a Lraves del mensa[e.
private hnal Handler progressHandler = new Handler() {
9? !"#$% '()#%*)
public void handleMessage(Message msg)
{ setData();
progressDialog.dismiss();
}
};
Carga de datos
La carga de daLos no cambla mucho, segulmos Lenlendo el dllogo de progreso pero ahora ya no nece-
slLamos mandar los daLos reconocldos por el parser a Lraves del mane[ador sl no puedo guardarlos en
la clase de apllcacln dlrecLamenLe y mando un mensa[e vaclo.
private void loadData() {
progressDialog = ProgressDialog.show(
Main.this,
,
Por favor espere mientras se cargan los datos...,
true);
new Thread(new Runnable(){
@Override
public void run() {
XMLParser parser = new XMLParser(feedUrl);
appState.setData(parser.parse());
progressHandler.sendEmptyMessage(0);
}}).start();
}
Agregando el men de opciones
neceslLamos lndlcarle que hacer cuando el usuarlo preslone la Lecla de menu en el Lelefono, como en
esLe caso consLrulmos el menu en un xML solo es necesarlo crear una lnsLancla.
@Override
9: !"#$% '()#%*)
public boolean onCreateOptionsMenu(Menu menu) {
MenuInHater inHater = getMenuInHater();
inHater.inHate(R.layout.menu, menu);
return true;
}
Adems, requerlmos sobrecargar oLra funcln que se dlspara cuando el usuarlo ellge alguna de las
opclones del menu. Aqul guardaremos en la clase de apllcacln lo que sea que el usuarlo haya elegldo.
@Override
public boolean onOptionsItemSelected(MenuItem item)
{ switch (item.getItemId()) {
case R.id.mmElementApp:
appState.setSelectedOption(APP_VIEW);
break;
case R.id.mmElementBrw:
appState.setSelectedOption(BROWSER_VIEW);
break;
}
return true;
}
Llamando todo desde la funcin onCreate
uenLro del cuerpo de la funcuon oCreaLe lnlclallzamos la varlable para nuesLra clase de apllcacln:
appState = ((MyApp)getApplication());
valldamos sl el lnLenL lo levanL alguna oLra AcuvlLy y sl vlene un -1 en el mensa[e mosLramos un error:
Intent it = getIntent();
int fromShowElement = it.getIntExtra(POSITION_KEY, 0);
if (fromShowElement == -1) {
Toast.makeText(this, Error, imposible visualizar el elemento,
Toast.LENGTH_LONG);
}
9! !"#$% '()#%*)
La accln sobre el cllck del boLn no cambla mucho, la verlcacln la hemos camblado y en lugar de ver
sl el adapLar ya uene daLos revlsamos sl la clase de apllcacln devuelve algo dlferenLe de null:
LinkedList data = appState.getData();
if (data != null) { . }
Conclusin

L|stAcnv|ty: aprendlmos la uullzacln de esLe upo de acuvldad que nos da algunas ayudas cuando
nuesLra acuvldad muesLra una llsLa de daLos.

0@,6)1&)2, Menu y MenulLem: en la parLe de dlseno, mane[amos lmagevlew para mosLrar lmge-
nes, en el caso de nuesLra apllcacln, la lmagen se obuene de una dlreccln de lnLerneL y los byLes
reclbldos se aslgnan para mosLrarla. 1amblen agregamos un menu con opclones MenulLems para
eleglr y colocar una conguracln muy slmple de nuesLra apllcacln.

Guardar datos a travs de c|ases de ap||cac|n: como un medlo de guardar el esLado de la apllca-
cln vlmos la forma de uullzar una clase creada por nosoLros y Lamblen los mecanlsmos para guar-
dar y recuperar los daLos guardados.

P%8$)5,$6,$ 5*,/)/ L,$, L)$/%",*&Q,5&7" R3:!#,L-)$S: con el n de personallzar la forma en que
se muesLran los daLos, uullzamos como base una clase ya exlsLenLe y modlcamos lo necesarlo
para que el renderlng fuera a nuesLro gusLo.

Inc|u|r Acnv|nes a nuestra ap||cac|n: la apllcacln puede conLener ms de una acuvlLy, vlmos lo
necesarlo para agregar y congurar en el manlfesL nuevas acuvlues.

Lnv|ar datos a travs de |ntents: uullzamos lnLenLs no solo para levanLar una nueva AcuvlLy sl no
Lamblen para envlarle daLos de una AcuvlLy a oLra.

kec|b|r datos a travs de |ntents: para lograr la comunlcacln enLre mls acuvlues no solo fue nece-
sarlo envlar los daLos sl no en la acuvlLy llamada Lamblen obLenerlos para su uullzacln.

También podría gustarte