Friday, August 6, 2010

Load List Items Forever

AIM:If you want to load your listview in background forever like processing in android market.

The following is a simple tutorial to make it .
 Step 1)  Create a activity as follows:  (MyListActivity.java)


public class MyListActivity extends ListActivity
{
    static final String LOG_TAG = "MyListActivity";

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        MyAdapter itemAdapter = new MyAdapter(  this, R.layout.item_row, R.layout.loading_row );
        setListAdapter( itemAdapter );
    }
}
2) create a adapter which will creates functionality for managing adapter. (MyAdapter.java)


public class MyAdapter extends BaseAdapter {

    private Context context;
private int itemRowResID;
    private int loadingRowResID;
    private int base;
    private int pageLen;
    int itemsLoaded;
    int itemsToLoad;
    boolean allItemsLoaded;
    Boolean loading;
    UIUpdateTask updateTask;
    static final int PRELOAD_ITEMS = 30;
    static final String LOG_TAG = "PAGEADAPTER";

    DataSource dataSource;
    ArrayList items;
    Handler uiHandler = new Handler();

    public MyAdapter( Context context,
                        int itemRowResID,
                        int loadingRowResID ) {
        this.context = context;
this.itemRowResID = itemRowResID;
        this.loadingRowResID = loadingRowResID;
        dataSource = new DataSource();
        itemsLoaded = 0;
        itemsToLoad = 0;
        items = new ArrayList();
        allItemsLoaded = false;
        loading = Boolean.FALSE;
        updateTask = new UIUpdateTask();
    }

    public int getCount() {
        int count = itemsLoaded;
        if( !allItemsLoaded )
            ++count;
        return count;
    }

    public Object getItem(int position) {
        String result;
        synchronized( items ) {
            result = items.get( position );
        }
        return result;
    }

    public long getItemId(int position) {
        return position;
    }

    public View getView(int position, View convertView, ViewGroup parent) {
        boolean isLastRow = position >= itemsLoaded;
        int rowResID = isLastRow ?
                    loadingRowResID :
                    itemRowResID;
        LayoutInflater inflater = LayoutInflater.from( context );
View v = inflater.inflate(  rowResID, parent, false );
        if( isLastRow ) {
            if ( position < dataSource.getItemCount() ) {
// Should there be more items loaded?
                int nextItemToLoad = position+PRELOAD_ITEMS;
                int allItemsToLoad = dataSource.getItemCount();
                if( nextItemToLoad > allItemsToLoad )
                    nextItemToLoad = allItemsToLoad;
                Log.d( LOG_TAG, "nextItemToLoad: "+nextItemToLoad );
                if( nextItemToLoad > itemsToLoad ) {
                    itemsToLoad = nextItemToLoad;
                    Log.d( LOG_TAG, "itemsToLoad: "+itemsToLoad );
// Launch the loading thread if it is not currently running
                    synchronized( loading ) {
                        if( !loading.booleanValue() ) {
                            Log.d( LOG_TAG, "Staring loading task" );
                            loading = Boolean.TRUE;
                            Thread t = new LoadingThread();
                            t.start();
                            Log.d( LOG_TAG, "Loading task started" );
                        }
                    }
                }
            } else
                uiHandler.post( updateTask );
        } else {
            String item = items.get( position );
   TextView itemControl = (TextView)v.findViewById( R.id.item );
   if( itemControl != null )
   itemControl.setText( item );
        }
        return v;
    }

    public boolean areAllItemsEnabled() {
        return true;
    }

    public boolean  isEnabled(int position) {
        return true;
    }

    class LoadingThread extends Thread {
        public void run() {
            int itemsOriginallyLoaded = 0;
            synchronized( items ) {
                itemsOriginallyLoaded = items.size();
            }
            for( int i = itemsOriginallyLoaded ; i < itemsToLoad ; ++i ) {
                Log.d( LOG_TAG, "Loading item #"+i );
                String item = dataSource.getItem( i );
                synchronized( items ) {
                    items.add( item );
                }
                itemsLoaded = i+1;
                uiHandler.post( updateTask );
                Log.d( LOG_TAG, "Published item #"+i );
            }
            if( itemsLoaded >= ( dataSource.getItemCount() - 1 ) )
                allItemsLoaded = true;
            synchronized( loading ) {
                loading = Boolean.FALSE;
            }
        }
    }

    class UIUpdateTask implements Runnable {
        public void run() {
            Log.d( LOG_TAG, "Publishing progress" );
            notifyDataSetChanged();
        }
    }
}
step 3) Finally create the datasource class which will fetch data from source.



public class DataSource {
    static final int ITEM_COUNT = 100;
    ArrayList items;

    public DataSource() {
        items = new ArrayList( ITEM_COUNT );
        for( int i = 0 ; i < ITEM_COUNT ; ++i )
            items.add( "item"+Integer.toString( i ) );
    }

    public int getItemCount() {
        return items.size();
    }

    public String getItem( int itemIndex ) {
// It's a slow data source
       try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
        return items.get( itemIndex );
    }

}

Step 4) Create a Layout  for main activity as follows :  (main.xml)

< Linear Layout
   x m l n s : android="http://schemas.android.com/apk/res/android"

    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
   >
   < List View android:id="@+id/android:list"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"/>
  < Text View android:id="@+id/android:empty"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:text="@string/main_no_items"/>
< / Linear Layout>

Step 5) Create a layout which  will display while items are loading.. (loading_row.xml)
< Linear Layout
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal"> 
    < Text View android:id="@+id/item"
         android : text Size="10 p x"
         android:textStyle="bold|italic"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:text="@string/list_loading"/>


< / Linear Layout>

 step 6) Create a layout for each row of the list  as follows:  (item_row.xml)

< Linear Layout

     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="fill_parent"
     android:layout_height="wrap_content"
     android:orientation="horizontal">
    < Text View 
         android:id="@+id/item"
         android : text Size="12px"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"/>
< / Linear Layout>
After creating all these build the project and run it.

6 comments:

  1. Congrats Ramamohan for presenting a wonderful Blog. I had ever seen such a Blog site for Android.

    ReplyDelete
  2. Hi ramamohan, this blog is useful for everyone..nice

    ReplyDelete
  3. Hi this is nice one

    ReplyDelete
  4. This is not the autogrowing list from the Market application. Please, don't post fake titles !

    ReplyDelete
  5. Hi Rama,

    Many many thanks to post this article.
    It really helped me a lot to write the code for loading the contacts list more responsive.

    ReplyDelete

Android Developers Blog

Ram's shared items