Android – Inserire una ListView con caricamenti parziali della lista sullo scorrimento

Se abbiamo una lista molto lunga e pesante da caricare sul nostro device Android, una delle soluzioni più comuni per risolvere il problema è quella di caricare porzioni di essa via via che si scorre con la visualizzazione.
Vi mostrerò di seguito il codice; prendete nota che si tratta di una lista “finita” di cui si conosce l’ammontare totale delle righe.

public class MyActivity extends Activity
{
	//Numero massimo di righe da recuperare per volta
	private static final int NUM_RECORD_X_PAG = 50;
	//Variabile in cui mettere il numero totale delle righe della mia lista
	private int totalRows; 

	private ListView listView;
	private MyAdapter listAdapter;
	private EndlessScrollListener listScrollListener;

	@Override
	protected void onCreate(Bundle savedInstanceState)
	{
		listView = (ListView) findViewById(R.id.listView);
		listAdapter = new MyAdapter();
		listView.setAdapter(listAdapter);
		listScrollListener = new EndlessScrollListener();
		listView.setOnScrollListener(listScrollListener);

		//Primo caricamento della lista
		LoadListTask task = new LoadListTask();
		task.execute();
	}

	//Adapter di appoggio per memorizzarsi la lista degli elementi visualizzati
	class MyAdapter extends BaseAdapter 
	{
		List listDisplayed = new ArrayList();

        public int getCount() { return listDisplayed.size(); }
        public Object getItem(int pos) { return listDisplayed.get(pos); }
        public long getItemId(int pos) { return pos; }

        public View getView(int pos, View v, ViewGroup p) 
		{
			TextView view = new TextView(Test.this);
			view.setText(listDisplayed.get(pos));
			return view;
        }

		public void setListDisplayed(List listDisplayed) { this.listDisplayed = listDisplayed; }
		public List getListDisplayed() { return this.listDisplayed; }
    }

	public class LoadListTask extends AsyncTask<Void, Void, List>
	{
		public LoadListTask() { }

		@Override
		protected List doInBackground(Void... params)
		{
			//Segnalo al mio listener di che sto facendo un caricamento
			listScrollListener.setLoading(true);

			int start = (listAdapter.getListDisplayed().size());

			//Qui carico la lista parziale partendo da "start" per "NUM_RECORD_X_PAG"
			List partialList = getList(start, NUM_RECORD_X_PAG);
			return partialList;
		}

		@SuppressWarnings("unchecked")
		@Override
		protected void onPostExecute(List partialList)
		{
			//Alla mia lista attualmente visualizzata aggiungo la lista parziale appena caricata
			listAdapter.getListDisplayed().addAll(partialList);

			//Se ho caricato tutte le righe segnalo al listener di non lanciare più caricamenti
			if (listAdapter.getListDisplayed().size() == totalRows)
				listScrollListener.setFinished(true);
			else
				listScrollListener.setFinished(false);

			listAdapter.notifyDataSetChanged();

			//Segnalo al mio listener di aver finito il caricamento
			listScrollListener.setLoading(false);
		}
	}

	public class EndlessScrollListener implements OnScrollListener
	{
		private boolean finished = false;
		private boolean loading = false;

		public EndlessScrollListener() { }

		@Override
		public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount)
		{
			boolean loadMore = firstVisibleItem + visibleItemCount >= totalItemCount;

			//Quando scrollo fino in fondo (loadMore), non c'è già un caricamento in corso (loading) e non ho già caricato tutta la lista (finished)
			if (loadMore && !finished && !loading && totalItemCount != 0)
			{
				LoadListTask task = new LoadListTask();
				task.execute();
			}
		}

		@Override
		public void onScrollStateChanged(AbsListView view, int scrollState) { }

		public boolean isFinished() { return finished; }
		public void setFinished(boolean finished) { this.finished = finished; }

		public boolean isLoading() { return loading; }
		public void setLoading(boolean loading) { this.loading = loading; }
	}
}

4 commenti

  • Ma il metodo getList(start, NUM_RECORD_X_PAG) dove lo trovo?

    Luca Reply
    • Quel metodo non è presente in quanto semplicemente quello che ritorna è la lista dei valori da mostrare nella listView. Nel mio caso all’interno di quel metodo io faccio una chiamata al Database.

      Giacomo Baccianti Reply
      • Ok, ora è tutto funzionante. L’unico problema è che le righe della listView vengono visualizzate molto piccole, cosa che non succedeva prima. Penso che dipenda dall’adapter: quando lo creavo io facevo

        mioAdapter = new ArrayAdapter (getApplicationContext(),android.R.layout.simple_list_item_1,lista);

        mentre lei fa

        listAdapter = new MyAdapter();

        Potrebbe essere dovuto dal android.R.layout.simple_list_item_1 ??

        Grazie in anticipo

        Luca Reply
      • Nulla risolto, scusate il disturbo.
        Il problema è un altro… che se scrollo tante volte su e giù si rallenta un sacco..

        Luca Reply

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *