Android: Custom Adapter ListView with ListFragment and LoaderManager inside FragmentActivity


Requirements:

You must have the android-support-v4.jar. (unless you don’t want to run your app on android version less than 3.0)

Listview with loaderManager

Our Model Class: Model.java


public class Model {

	private String name;
	private String id;

	public Model(String name, String id) {
		this.name = name;
		this.id = id;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

}

Custom adapter: CustomArrayAdapter.java


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

public class CustomArrayAdapter extends ArrayAdapter<Model> {
    private final LayoutInflater mInflater;

    public CustomArrayAdapter(Context context) {
        super(context, android.R.layout.simple_list_item_2);
        mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    }

    public void setData(List<Model> data) {
        clear();
        if (data != null) {
            for (Model appEntry : data) {
                add(appEntry);
            }
        }
    }

    /**
     * Populate new items in the list.
     */
    @Override public View getView(int position, View convertView, ViewGroup parent) {
        View view;

        if (convertView == null) {
            view = mInflater.inflate(R.layout.single_item, parent, false);
        } else {
            view = convertView;
        }

        Model item = getItem(position);
        ((TextView)view.findViewById(R.id.tv_label)).setText(item.getName());
        ((TextView)view.findViewById(R.id.tv_id)).setText(item.getId());

        return view;
    }
} 

List Activity: MyListActivity.java


import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.os.Bundle;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.ListFragment;
import android.support.v4.app.LoaderManager;
import android.support.v4.content.AsyncTaskLoader;
import android.support.v4.content.Loader;

public class MyListActivity extends FragmentActivity {
	
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // to give support on lower android version, we are not calling getFragmentManager() 
        FragmentManager fm = getSupportFragmentManager();

        // Create the list fragment and add it as our sole content.
        if (fm.findFragmentById(android.R.id.content) == null) {
        	DataListFragment list = new DataListFragment();
            fm.beginTransaction().add(android.R.id.content, list).commit();
        }
    }
    
    public static class DataListFragment extends ListFragment implements LoaderManager.LoaderCallbacks<List<Model>> {
    	
        CustomArrayAdapter mAdapter;

        @Override public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);
            
            System.out.println("DataListFragment.onActivityCreated");

            // Initially there is no data 
            setEmptyText("No Data Here");

            // Create an empty adapter we will use to display the loaded data.
            mAdapter = new CustomArrayAdapter(getActivity());
            setListAdapter(mAdapter);

            // Start out with a progress indicator.
            setListShown(false);

            // Prepare the loader.  Either re-connect with an existing one,
            // or start a new one.
            getLoaderManager().initLoader(0, null, this);
        }

        @Override 
        public void onListItemClick(ListView l, View v, int position, long id) {
            // Insert desired behavior here.
            Log.i("DataListFragment", "Item clicked: " + id);
        }

		@Override
		public Loader<List<Model>> onCreateLoader(int arg0, Bundle arg1) {
			System.out.println("DataListFragment.onCreateLoader");
			return new DataListLoader(getActivity());
		}

		@Override
		public void onLoadFinished(Loader<List<Model>> arg0, List<Model> data) {
			mAdapter.setData(data);
			System.out.println("DataListFragment.onLoadFinished");
            // The list should now be shown.
            if (isResumed()) {
                setListShown(true);
            } else {
                setListShownNoAnimation(true);
            }
		}

		@Override
		public void onLoaderReset(Loader<List<Model>> arg0) {
			mAdapter.setData(null);
		}
    }
    
    public static class DataListLoader extends AsyncTaskLoader<List<Model>> {
    	
    	List<Model> mModels;

		public DataListLoader(Context context) {
			super(context);
		}

		@Override
		public List<Model> loadInBackground() {
			System.out.println("DataListLoader.loadInBackground");
			
			 // You should perform the heavy task of getting data from 
			 // Internet or database or other source 
			 // Here, we are generating some Sample data

            // Create corresponding array of entries and load with data.
            List<Model> entries = new ArrayList<Model>(5);
            entries.add(new Model("Java", "2"));
            entries.add(new Model("C++", "9"));
            entries.add(new Model("Python", "6"));
            entries.add(new Model("JavaScript", "10"));

            return entries;
		}
		
        /**
         * Called when there is new data to deliver to the client.  The
         * super class will take care of delivering it; the implementation
         * here just adds a little more logic.
         */
        @Override public void deliverResult(List<Model> listOfData) {
            if (isReset()) {
                // An async query came in while the loader is stopped.  We
                // don't need the result.
                if (listOfData != null) {
                    onReleaseResources(listOfData);
                }
            }
            List<Model> oldApps = listOfData;
            mModels = listOfData;

            if (isStarted()) {
                // If the Loader is currently started, we can immediately
                // deliver its results.
                super.deliverResult(listOfData);
            }

            // At this point we can release the resources associated with
            // 'oldApps' if needed; now that the new result is delivered we
            // know that it is no longer in use.
            if (oldApps != null) {
                onReleaseResources(oldApps);
            }
        }

        /**
         * Handles a request to start the Loader.
         */
        @Override protected void onStartLoading() {
            if (mModels != null) {
                // If we currently have a result available, deliver it
                // immediately.
                deliverResult(mModels);
            }


            if (takeContentChanged() || mModels == null) {
                // If the data has changed since the last time it was loaded
                // or is not currently available, start a load.
                forceLoad();
            }
        }

        /**
         * Handles a request to stop the Loader.
         */
        @Override protected void onStopLoading() {
            // Attempt to cancel the current load task if possible.
            cancelLoad();
        }

        /**
         * Handles a request to cancel a load.
         */
        @Override public void onCanceled(List<Model> apps) {
            super.onCanceled(apps);

            // At this point we can release the resources associated with 'apps'
            // if needed.
            onReleaseResources(apps);
        }

        /**
         * Handles a request to completely reset the Loader.
         */
        @Override protected void onReset() {
            super.onReset();

            // Ensure the loader is stopped
            onStopLoading();

            // At this point we can release the resources associated with 'apps'
            // if needed.
            if (mModels != null) {
                onReleaseResources(mModels);
                mModels = null;
            }
        }

        /**
         * Helper function to take care of releasing resources associated
         * with an actively loaded data set.
         */
        protected void onReleaseResources(List<Model> apps) {}
    	
    }
}

single_item.xml

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

    <TextView
        android:id="@+id/tv_label"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Label"
        android:textSize="20sp" >
    </TextView>
    
    <TextView
        android:id="@+id/tv_id"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="Sample Id"
        android:textSize="20sp" >
    </TextView>
</LinearLayout> 
Advertisements

14 thoughts on “Android: Custom Adapter ListView with ListFragment and LoaderManager inside FragmentActivity

  1. can some one please reply me public void setData(List data) {
    clear();
    if (data != null) {
    for (Model appEntry : data) {
    add(appEntry);
    }
    }
    }
    what is add() function and where is the implementation ? i am getting error in this point

  2. @nida
    add() method is in base ArrayAdapter class. as you can see,
    CustomArrayAdapter extends ArrayAdapter

    you can find the latest ArrayAdapter implementation here or here

  3. I HAVE Followed this tutorial but getting error
    01-09 21:17:58.220: E/AndroidRuntime(12287): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mrfs.android.surveyapp/com.mrfs.android.surveyapp.activities.LocationListActivity}: java.lang.IllegalStateException: Content view not yet created
    01-09 21:17:58.220: E/AndroidRuntime(12287): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2100)
    01-09 21:17:58.220: E/AndroidRuntime(12287): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2125)

  4. can some one define me these LOC ?
    public class MyListActivity extends FragmentActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // to give support on lower android version, we are not calling getFragmentManager()
    FragmentManager fm = getSupportFragmentManager();

    // Create the list fragment and add it as our sole content.
    if (fm.findFragmentById(android.R.id.content) == null) {
    DataListFragment list = new DataListFragment();
    fm.beginTransaction().add(android.R.id.content, list).commit();
    }
    }
    WHAT IS content ?

  5. i need to set image view here
    Model item = getItem(position);
    ((TextView)view.findViewById(R.id.tv_label)).setText(item.getName());
    ((TextView)view.findViewById(R.id.tv_id)).setText(item.getId());
    ((ImageView)view.findViewById(R.id.tick)).setText(item.getId());
    can i do like this? what are modification i have to do in other classes for this?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s