Android ListView: Estrategias de paginación (I)


VERSIONES

  1. 10/06/2012 (Primera publicación)
  2. 25/06/2012:
    • Detección completa del último elemento del ListView
  3. 07/08/2013:
    • Actualizado el proyecto en GitHub: Actualizado y probado con Jelly Bean 4.3, Traducción español,Iconos

android

ListView es uno de los componentes gráficos más importantes y utilizados de Android SDK. Al utilizarlo tarde o temprano nos veremos en la necesidad de “paginar” los elementos mostrados cuando el volumen de datos sea muy elevado y/o la obtención de estos datos tenga un coste importante, por ejemplo datos a recuperar remotamente a través de servicios web.

Android SDK no proporciona mecanismo alguno para realizar esta tarea pero es relativamente sencillo implementar esta funcionalidad. En este mini-tutorial se van a presentar tres estrategias  de paginación , incluyendo una sencilla implementación de ejemplo para cada una.

Entorno de pruebas:

Requisitos: Conocimientos básicos de Android y Eclipse ADT, haber utilizado ListView.

Aplicación de pruebas

Para este tutorial se va a crear una única app que sirva de demo para las tres estrategias propuestas. La pantalla principal mostrará tres botones para acceder a un listado paginado siguiendo la estrategia correspondiente.

Primeramente, creamos un proyecto con el asistente de Eclipse ADT para Android 2.1 (API 7) que voy a denominar “Paginated ListView Demo”.

New Android Project

Reutilizamos el main.xml con el “Hello World” creado por el asistente para el layout (menu.xml) que mostrará los tres botones que necesitamos. Se usará además la propiedad “onClick” para establecer qué método se ejecutará al pulsar cada botón.

<?xml version="1.0" encoding="utf-8"?>

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <Button
        android:id="@+id/buttonEndless"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="40dp"
        android:onClick="endless"
        android:text="@string/endless" />

    <Button
        android:id="@+id/buttonLoad"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/buttonEndless"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:layout_marginTop="40dp"
        android:onClick="loadmore"
        android:text="@string/loadmorebutton" />

    <Button
        android:id="@+id/buttonButtons"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/buttonLoad"
        android:layout_centerHorizontal="true"
        android:layout_centerVertical="true"
        android:layout_marginTop="40dp"
        android:onClick="buttons"
        android:text="@string/buttons" />

</RelativeLayout>

Como buena práctica, seguimos la recomendación de definir los literales en el fichero correspondiente /res/values/strings.xml.

<?xml version="1.0" encoding="utf-8"?>
<resources>

    <string name="app_name">Paginated ListView Demo - danielme.com</string>
    <string name="endless">Endless ListView</string>
    <string name="loadmorebutton">Load More Button</string>
    <string name="buttons">Paging Buttons</string>
    <string name="notyet">Demo not yet implemented</string>
    <string name="test">test</string>


</resources>

La Activity se ubicará en el paquete com.danielme.blog.android.paginatedlistview.activities y de momento sólo contendrá la definición de los métodos asociados a los botones.

package com.danielme.blog.android.paginatedlistview.activities;

import com.danielme.blog.android.paginatedlistview.R;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Toast;

public class MenuActivity extends Activity 
{
	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.menu);
	}
	
	public void endless(View button)
	{
		Toast.makeText(this, getString(R.string.notyet), Toast.LENGTH_SHORT).show();
	}
	
	public void loadmore(View button)
	{
		Toast.makeText(this, getString(R.string.notyet), Toast.LENGTH_SHORT).show();
	}
	
	public void buttons(View button)
	{
		Toast.makeText(this, getString(R.string.notyet), Toast.LENGTH_SHORT).show();
	}
}
	

menu

ListView

Usaremos como Listview un ejemplo sencillo pero realista. Para cada fila se usará el siguiente layout (listview.xml)

ADT Layout Editor


<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ImageView
        android:id="@+id/imageView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentLeft="true"
        android:layout_alignParentTop="true"
        android:src="@drawable/ic_launcher" />
    
     <TextView
        android:id="@+id/textView1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_marginLeft="5dp"
        android:layout_toRightOf="@+id/imageView1"
        android:text="@string/test"
        android:textAppearance="?android:attr/textAppearanceLarge" />

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBottom="@+id/imageView1"
        android:layout_marginLeft="5dp"
        android:layout_toRightOf="@+id/imageView1"
        android:text="@string/test"
        android:textAppearance="?android:attr/textAppearanceSmall" />
   

</RelativeLayout>

Utilizar este layout requiere la implementación de un Adapter propio y personalizado. Utilizaremos la típica implementación-plantilla basada en el View Holder Pattern, en mi caso he optado por especializar la clase ArrayAdapter y utilizar como Holder la siguiente clase pública:

package com.danielme.blog.android.paginatedlistview;

import android.widget.TextView;

public class Holder
{

	private TextView textView1;

	private TextView textView2;

	public TextView getTextView1()
	{
		return textView1;
	}

	public void setTextView1(TextView textView)
	{
		this.textView1 = textView;
	}

	public TextView getTextView2()
	{
		return textView2;
	}

	public void setTextView2(TextView textView)
	{
		this.textView2 = textView;
	}
}

Usando esta clase, el adapter quedará así:

package com.danielme.blog.android.paginatedlistview;

import java.util.List;

import com.danielme.blog.android.paginatedlistview.R;


import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;

/**
 * Custom adapter with "View Holder Pattern".
 * @author danielme.com
 *
 */
public class CustomArrayAdapter extends ArrayAdapter<String>
{

	public CustomArrayAdapter(Context context, int textViewResourceId, List<String> objects)
	{
		super(context, textViewResourceId, objects);	
	}

	
	@Override
	public View getView(int position, View convertView, ViewGroup parent)
	{
		// holder pattern
		Holder holder = null;
		if (convertView == null)
		{
			holder = new Holder();

			LayoutInflater layoutInflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
			convertView = layoutInflater.inflate(R.layout.listview, null);
			holder.setTextView1((TextView) convertView.findViewById(R.id.textView1));
			holder.setTextView2((TextView) convertView.findViewById(R.id.textView2));
			convertView.setTag(holder);
		}
		else
		{
			holder = (Holder) convertView.getTag();
		}

		holder.getTextView1().setText(getItem(position));
		holder.getTextView2().setText(getItem(position));
		return convertView;
	}


}

Ya tenemos el “puzzle” casi completo: la última pieza es la fuente de datos que mostrará el ListView. Para poder paginar el ListView la clase que utilicemos deberá proporcionar un método que devuelva exactamente el subconjunto de datos que queremos mostrar. También nos simplifica el trabajo el hecho de conocer de antemano el número total de elementos que puede ser mostrado.

package com.danielme.blog.android.paginatedlistview;

import java.util.ArrayList;
import java.util.List;

/**
 * Test data.
 * @author danielme.com
 *
 */
public class Datasource
{
	//Singleton pattern
	private static Datasource datasource = null;
	
	private List<String> data = null;
	
	private static final int SIZE = 74;
	
	public static Datasource getInstance()
	{
		if (datasource == null)
		{
			datasource = new Datasource();
		}
		return datasource;
	}
	
	private Datasource()
	{
		data = new ArrayList<String>(SIZE);
		for (int i =1 ; i <= SIZE; i++)
		{
			data.add("row " + i);
		}		
	}
	
	public int getSize()
	{
		return SIZE;
	}
	
	/**
	 * Returns the elements in a <b>NEW</b> list.
	 */
	public List<String> getData(int offset, int limit)
	{
		List<String> newList = new ArrayList<String>(limit);
		int end = offset + limit;
		if (end > data.size())
		{
			end = data.size();
		}
		newList.addAll(data.subList(offset, end));
		return newList;		
	}

}

Y listo. Ya tenemos todo el código necesario para ir implementando las estrategias de paginación.

Endless ListView

La primera solución propuesta es probablemente la más utilizada y consiste en ir obteniendo y mostrando los datos en el ListView a medida que el usuario va haciendo scroll hasta el final del ListView; los datos se obtienen en segundo plano por lo que la aplicación puede seguir siendo utilizada mientras tanto.Es una estrategia recomendable en los casos en que los elementos más relevantes para el usuario sean los primeros de la lista, véase por ejemplo un cliente de email o de Twitter.

Para encontrar implementaciones de esta estrategia simplemente tenemos que irnos a nuestros dispositivos con Android y abrir Gmail o Google Store:

Google Store

Vamos a usar el siguiente layout (endless.xml).


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <TextView
        android:id="@+id/displaying"
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:layout_marginTop="5dp"
        android:gravity="center_horizontal"
        android:textSize="13sp" />

    <ListView
        android:id="@android:id/list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:layout_marginTop="5dp"
        android:drawSelectorOnTop="false" >
    </ListView>

</LinearLayout>

Además de mostrar el ListView se ha incluido una leyenda que informará al usuario de los elementos mostrados y disponibles.

    <string name="display">Displaying %1$s of %2$s</string>

Se crea en primer lugar la Activity sin paginación (y se añade al manifest), y a continuación añadimos el código necesario (creo que así se verá más claro):

package com.danielme.blog.android.paginatedlistview.activities;

import android.app.ListActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.danielme.blog.android.paginatedlistview.CustomArrayAdapter;
import com.danielme.blog.android.paginatedlistview.Datasource;
import com.danielme.blog.android.paginatedlistview.R;

/**
 * 
 * @author http://danielme.com
 * 
 */
public class EndlessListViewActivity extends ListActivity
{

	private Datasource datasource;

	private static final int PAGESIZE = 10;

	private TextView textViewDisplaying;	


	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		setContentView(R.layout.endless);
		datasource = Datasource.getInstance();			
		
		setListAdapter(new CustomArrayAdapter(this, R.layout.listview, datasource.getData(0, PAGESIZE)));
		
		updateDisplayingTextView();

	}
	
	
	private void updateDisplayingTextView()
	{
		textViewDisplaying = (TextView) findViewById(R.id.displaying);
		String text = getString(R.string.display);
		text = String.format(text, getListAdapter().getCount(), datasource.getSize());
		textViewDisplaying.setText(text);		
	}

	@Override
	protected void onListItemClick(ListView l, View v, int position, long id)
	{
		Toast.makeText(this, getListAdapter().getItem(position) + " " + getString(R.string.selected), Toast.LENGTH_SHORT).show();
	}

}

Ejecutando la Activity desde el botón correspondiente del menú, podemos ver que tal queda nuestra ListView:

public void endless(View button)
	{
		startActivity(new Intent(this, EndlessListViewActivity.class));
	}

ListView

Ahora, implementamos la paginación paso a paso:

  1. Footer:Necesitamos un footer que informe al usuario que se está realizando el proceso de carga. ListView proporciona esta funcionalidad, y lo único que tenemos que hacer es definir el contenido de ese footer en un layout por lo que tenemos libertad absoluta para diseñarlo. Voy a optar por un ProgressBar que sólo muestre el típico círculo giratorio (la animación dependerá de cada dispositivo y/o versión de Android). El contenido de mi footer.xml es el siguiente:
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:gravity="center_horizontal"
        android:orientation="horizontal"
        android:padding="3dp" >
    
        <ProgressBar
            android:id="@+id/progressBar1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:indeterminateOnly="true" />
    
    </LinearLayout>
    

    Desconozco el motivo, pero el footer hay que añadirlo al ListView antes que el adapter. Luego podremos mostrarlo y ocultarlo cuando queramos

    footerView = ((LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.footer, null, false);
    getListView().addFooterView(footerView, null, false);		
    setListAdapter(new CustomArrayAdapter(this, R.layout.listview, datasource.getData(0, PAGESIZE)));
    getListView().removeFooterView(footerView);
    
    
  2. Detectar cuándo hay que cargar los datos, esto es, controlar si el usuario ha hecho scroll hasta el final de los datos y quedan elementos por mostrar. En caso afirmativo, se mostrará el footer y se procederá a la obtención de la siguiente página de datos en un nuevo hilo para no bloquear la pantalla.Para ello hay que implementar y añadir al ListView un OnScrollListener:

    	getListView().setOnScrollListener(new OnScrollListener()
    		{			
    			@Override
    			public void onScrollStateChanged(AbsListView arg0, int arg1)
    			{
    				// nothing here				
    			}
    			
    			@Override
    			public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
    			{
    				boolean lastItem = (firstVisibleItem + visibleItemCount == totalItemCount);
    				boolean moreRows = getListAdapter().getCount() < datasource.getSize();
    				
    				if (!loading &&  lastItem && moreRows)
    				{
    					loading = true;
    					getListView().addFooterView(footerView, null, false);
    					(new LoadNextPage()).execute("");					
    				}				
    			}
    		});
    

    Obsérvese se ha añadido a la Activity el campo loading de tipo boolean. Esto es debido a que tenemos que evitar que mientras se obtengan los nuevos datos si el usuario vuelve a hacer scroll hasta el final del ListView no se solicite nuevamente la carga de esos datos y, por lo tanto, que se lancen nuevos e innecesarios hilos. Si esta casuística no se tuviera en cuenta, la consecuencia sería la posible inclusión en el ListView de datos duplicados.

  3. Implementar la obtención de los datos en segundo plano. Android nos lo pone muy fácil gracias a la clase AsyncTask, la especializamos en la clase privada LoadNextPage e implementamos dos métodos:
    • doInBackground: realiza las tareas “pesadas” y que generalmente no implican modificar la vista. En nuestro caso, simplemente llama al datasource. Le he añadido un sleep para que dé tiempo a ver el footer😉
    • onPostExecute: actualiza la vista añadiendo los nuevos datos al adapter y eliminando el footer
    private class LoadNextPage extends AsyncTask<String, Void, String>
    		{			
    			private List<String> newData = null;
    			@Override
    			protected String doInBackground(String... arg0)
    			{
    				//para que de tiempo a ver el footer😉
    				try
    				{
    					Thread.sleep(1500);
    				}
    				catch (InterruptedException e)
    				{
    					Log.e("EndlessListView", e.getMessage());					
    				}
    				   newData = datasource.getData(getListAdapter().getCount(), PAGESIZE);
    				   return null;
    			}
    			
    			@Override
    			protected void onPostExecute(String result)
    			{				
    				CustomArrayAdapter customArrayAdapter = ((CustomArrayAdapter) getListAdapter());
    				for (String value : newData)
    				{
    				 customArrayAdapter.add(value);
    				}
    				customArrayAdapter.notifyDataSetChanged();
    					
    				getListView().removeFooterView(footerView);
    				updateDisplayingTextView();
    				loading = false;
    			}
    			
    		}
    

Ya sólo nos resta ejecutar la aplicación y comprobar los resultados

Endless ListView Demo

Endless ListView Demo - 2

[Actualización]

En el código anterior se detecta si se está mostrando en pantalla el último elemento de la lista, pero no garantiza que se esté mostrando en su totalidad. Si queremos este último comportamiento se puede utilizar la siguiente versión de la variable lastItem:

		boolean lastItem = firstVisibleItem + visibleItemCount == totalItemCount && getListView().getChildAt(visibleItemCount -1) != null && getListView().getChildAt(visibleItemCount-1).getBottom() <= getListView().getHeight();

Código de ejemplo

Proyecto para Eclipse ADT publicado en GitHub. Para más información sobre cómo utilizar GitHub, consultar este artículo

Nota: El proyecto es el ejemplo completo de las dos partes del artículo. Asimismo, parte del código común se ha abstraído en una superclase.

23 Responses to Android ListView: Estrategias de paginación (I)

  1. Carlos dice:

    This is the best article i found!! you are the best!! thanks!!!

  2. Requiem55 dice:

    Como puedes hacer que el textView1 y el textView2 sean distintos datos, por ejemplo que uno ponga “row 1”, y otro “subtitulo row1”.

    Por lo demás, Gran tutorial!

    • danielme.com dice:

      En las líneas 49-50 del custom adapter.

      El contenido de un ListView se establece en el método getView del Adapter que se le pase. Por defecto el Adapter simplemente imprime en cada fila el resultado del toString(), por lo que si queremos que cada fila tenga un layout propio como en este ejemplo hay que implementar un Adapter personalizado para primero establecer ese layout con el inflater y luego rellenarlo con los datos.

      La clase Holder se suele utilizar por eficiencia ya que es más rápido aceder a los widgets de cada fila directamente por referencia que utilizar findViewById.

      • Requiem55 dice:

        Gracias, ya lo había solucionado, me costo bastante, pero todo fue bien.
        En Datasource cree un ArrayList por cada texview del xml y recogi el valor con los getItem.
        No se si fue lo más correcto, pero funciono, ahora me queda pasar el ListActivity a Fragmentlist y con un poco de maña introducirlo a un Viewpager. y ya seria mas o menos a lo de google play.

        Un saludo!

  3. beto dice:

    quisiera que me ayudaras con una aplicacion en la que quiero utilizar el endless, mi aplicacion ya funciona solo que quiero agregaarle esta funcion, hace lo siguiente

    tendo en edittext y debajo un list view,
    la funcion del edit text es que me cargue el list view mediante un web service al mismo tiempo que etoy escribiendo enviando el texto como parametro.

    el web service me regresa las 20 primeras coincidencias y lo que quiero hacer es que cuado llegue al final de la lista se ejecute de nuevo el web service con los mismo parametros solo qe ahora me regresara los siguientes 20 resultados,
    en el web service yo controlo cual pag deseo solo la envio como parametro

    todo esto lo ejecuto mediante el AsyncTask que me carga el listview en el evento textChanged del edit text

  4. beto dice:

    ya logre que me cargara la lista con el scroll pero sin el progressbar ya que cuando agrego el progres bar siempre me maraca el errror siguiente:

    FATAL EXCEPTION: main
    java.lang.NullPointerException
    at android.widget.ListView.clearRecycledState(ListView.java:504)
    at android.widget.ListView.resetList(ListView.java:491)
    at android.widget.ListView.setAdapter(ListView.java:422)

    esto es cada que entra en este punto:
    lvProductos.addFooterView(footerView, null, false); <– aqui es donde marca el error

    ya agregue primero el footerview y despues el setAdapter y al reves tambien

  5. beto dice:

    tamb me marca el siguiente error aqui:
    footerView = ((LayoutInflater) this.getSystemService(Context.LAYOUT_INFLATER_SERVICE)).inflate(R.layout.progress_bar, null, false);

    el error es:
    FATAL EXCEPTION: main
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.wsproducto/com.example.wsproducto.ProdActivity}: java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2663)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2679)
    at android.app.ActivityThread.access$2300(ActivityThread.java:125)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2033)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:123)
    at android.app.ActivityThread.main(ActivityThread.java:4627)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:521)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
    at dalvik.system.NativeStart.main(Native Method)
    Caused by: java.lang.UnsupportedOperationException: addView(View, LayoutParams) is not supported in AdapterView
    at android.widget.AdapterView.addView(AdapterView.java:461)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:622)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:407)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:320)
    at bms.example.wsproducto.ProdActivity.onCreate(ProdActivity.java:63)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1047)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2627)
    … 11 more

  6. beto dice:

    Saludos me sirvio de mucho el ejemplo este Espero y puedas ayudarme con otra app que estoy haciendo
    En esta app es tengo mi base de datos en el SQLite, tengo una tabla con 3 campos, codprod,descripcion, imagen
    solo tengo 2 edittext uno para el codigo y otro para la descripcion, lo que mi app hace es que conforme yo escribo en la descripcion este realiza una consulta y me regresa los productos que coincidadn con el texto y me los mustra en el listview (solo la descripcion). hasta aqui todo funciona bien
    Ahora lo que quiero hacer es que cuando yo seleccione algun producto de la lista automaticamente me agregue el cod en el textedit de codigo.

    mi preguta es
    hay alguna manera de tener los 2 valores en la lista (codprod y descripcion) pero solo mostrar uno y que cuando lo seleccione me tome el otro valor ????

    no se si me explique bien si sabes como puedo hacerlo o donde puedo encontrar algo similar

    • danielme.com dice:

      Al widget de la descripción puedes hacerle un setTag cuando le pongas su texto y guardar ahí una referencia a cualquier objeto, por ejemplo la cadena con el código. No sé si es lo que buscas.

  7. Alvaro dice:

    Andaba buscando como agregar items al list view desde un hilo secundario, y este post me sirvió de mucho.

  8. Angel dice:

    como puedo hacer que el puntero se mantenga en el ultimo item que se mostro antes de a actualizacion gracias por tu tutotial me ha ayudado

  9. Angell M.C. dice:

    funcion implementada gracias por tu aportacion solo una duda ojala y puedas ayudarme necesito que al momento de mostrar el load y me cargue los siguientes datos me mantenga siempre en el ultimo item para seguir haciendo scroll porque por ahora me regresa a primer item y tengo que volver a recorrer todo hasta llegar a los nuevos

    • Angell M.C. dice:

      resuelto jejejeje tenia puesto e dataseradapter antes del notifyDatechanged algo asi jejeje gracias de todas maneras

  10. Angell M.C. dice:

    tengo una duda donde puedo el id unico de un dispsitivo android pues parece haber gran controversia en ello debido a las versiones y caracteristicas de estos dispositivos lo que necesito es una identificacion unica q me permita consultarlo en la base de datos y asi permitirle acceso a esa informacion lo que se pretende evitar es solicitar usuario y contraseña debido a la informacion que se maneja

    • danielme.com dice:

      Nunca he hecho nada parecido pero hay un servicio que te permite acceder a algunos datos de la SIM y el dispositivo, quizás te sirva para identificar automáticamente un usuario. El problema lo podrías tener en dispositvos sin SIM p. ej. tablets.

  11. Juan Perez dice:

    Buen post, esta bien explicado y todo salio bien (Y).

    Pero tengo una duda, quise adaptar tu ejemplo usando una BD, pero como le doy los valores a los TextView para que me los muestre.

    De que manera tendria que modificar el datasource para que me devuelva los datos y q otras clases deberia de modificar. Gracias

  12. Ariel Diaz dice:

    Muy bueno el aporte, la duda mía como cambias la imagen según la posición del listview?,

  13. Katty dice:

    Muchas gracias señor, es justo lo que necesitaba😀

  14. yesez5 dice:

    Excelente ejemplo, me sirvió mucho, lo adapté para que funcionara con peticiones asíncronas HTTP usando Volley

  15. Jonathan dice:

    Hola, tengo varios problemas con este ejemplo, mi app se basa en recoger, mediante rss, los articulos de una pagina web, maneja esa info en una clase aparte, porque no necesito todo lo que trae el rss, y también implemento mi propio adapter, el detalle esta en que no puedo adaptarlo para que funcione en mi aplicación, simplemente necesito que no cargue todos los articulos porque demora mucho (son mas de 100).

    Espero que alguien me pueda ayudar ya que veo que este post algo antiguo.
    Gracias de antemano.
    Saludos!

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: