I have a ListFragment
, in the list of which the Albums of the device and the associated artist should be displayed using the MediaStore
. Thus, each row has two TextViews
. I use LoaderManager
and CursorLoader
to populate the list up, using a special CursorAdapter to bind TextViews
to a string to data.
List Code:
public class AlbumsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> { AlbumsAdapter mAdapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View myFragmentView = inflater.inflate(R.layout.albums_fragment_layout, container, false); return myFragmentView; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); setListAdapter(mAdapter); getLoaderManager().initLoader(0, null, this); } static final String[] ALBUM_SUMMARY_PROJECTION = { MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Albums.ARTIST}; public Loader<Cursor> onCreateLoader(int id, Bundle args) { String select = null; return new CursorLoader(getActivity(), MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,ALBUM_SUMMARY_PROJECTION, select, null, null); } public void onLoadFinished(Loader<Cursor> loader, Cursor data) { mAdapter.swapCursor(data); } public void onLoaderReset(Loader<Cursor> loader) { mAdapter.swapCursor(null); } }
AlbumsAdapter (Custom CursorAdapter) Code:
public class AlbumsAdapter extends CursorAdapter { private final LayoutInflater mInflater; public AlbumsAdapter(Context context, Cursor c) { super(context, c); mInflater=LayoutInflater.from(context); } @Override public void bindView(View view, Context context, Cursor cursor) { TextView albumTitle =(TextView)view.findViewById(R.id.albumTextView); albumTitle.setText(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ALBUM))); TextView artistName=(TextView)view.findViewById(R.id.artistTextView); artistName.setText(cursor.getString(cursor.getColumnIndex(MediaStore.Audio.Albums.ARTIST))); } @Override public View newView(Context context, Cursor cursor, ViewGroup parent) { final View view=mInflater.inflate(R.layout.albums_row,parent,false); return view; }
At the moment, when I show this ListFragment, I have java.lang.NullPointerException, here is logCat:
06-14 09:39:23.109: W/dalvikvm(8632): threadid=1: thread exiting with uncaught exception (group=0x40c2d1f8) 06-14 09:39:23.109: E/AndroidRuntime(8632): FATAL EXCEPTION: main 06-14 09:39:23.109: E/AndroidRuntime(8632): java.lang.NullPointerException 06-14 09:39:23.109: E/AndroidRuntime(8632): at com.music.pod.AlbumsFragment.onLoadFinished(AlbumsFragment.java:61) 06-14 09:39:23.109: E/AndroidRuntime(8632): at com.music.pod.AlbumsFragment.onLoadFinished(AlbumsFragment.java:1) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.app.LoaderManagerImpl$LoaderInfo.callOnLoadFinished(LoaderManager.java:438) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.app.LoaderManagerImpl$LoaderInfo.onLoadComplete(LoaderManager.java:406) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.content.Loader.deliverResult(Loader.java:125) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.content.CursorLoader.deliverResult(CursorLoader.java:88) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.content.CursorLoader.deliverResult(CursorLoader.java:42) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.content.AsyncTaskLoader.dispatchOnLoadComplete(AsyncTaskLoader.java:236) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.content.AsyncTaskLoader$LoadTask.onPostExecute(AsyncTaskLoader.java:76) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.os.AsyncTask.finish(AsyncTask.java:602) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.os.AsyncTask.access$600(AsyncTask.java:156) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.os.AsyncTask$InternalHandler.handleMessage(AsyncTask.java:615) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.os.Handler.dispatchMessage(Handler.java:99) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.os.Looper.loop(Looper.java:137) 06-14 09:39:23.109: E/AndroidRuntime(8632): at android.app.ActivityThread.main(ActivityThread.java:4507) 06-14 09:39:23.109: E/AndroidRuntime(8632): at java.lang.reflect.Method.invokeNative(Native Method) 06-14 09:39:23.109: E/AndroidRuntime(8632): at java.lang.reflect.Method.invoke(Method.java:511) 06-14 09:39:23.109: E/AndroidRuntime(8632): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:790) 06-14 09:39:23.109: E/AndroidRuntime(8632): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:557) 06-14 09:39:23.109: E/AndroidRuntime(8632): at dalvik.system.NativeStart.main(Native Method)
Could you help me correct my code so that the album and the artist associated with it appear in the list?
Problem resolved:
For those trying to populate a custom listview with Album, Artist, etc. using the LoaderManager / CursorLoader method, you must:
1) Create your own custom CursorAdapter that associates the TextViews of your string with cursor data (see my custom CursorAdapter above)
2) Then in your fragment here what to do:
public class AlbumsFragment extends ListFragment implements LoaderManager.LoaderCallbacks<Cursor> { AlbumsAdapter mAdapter; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View myFragmentView = inflater.inflate(R.layout.albums_fragment_layout, container, false); return myFragmentView; } @Override public void onActivityCreated(Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); mAdapter = new AlbumsAdapter(getActivity(), null); setListAdapter(mAdapter); getLoaderManager().initLoader(0, null, this); } static final String[] ALBUM_SUMMARY_PROJECTION = { MediaStore.Audio.Albums._ID, MediaStore.Audio.Albums.ALBUM, MediaStore.Audio.Albums.ARTIST}; public Loader<Cursor> onCreateLoader(int id, Bundle args) { String select = null; return new CursorLoader(getActivity(), MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI,ALBUM_SUMMARY_PROJECTION, select, null, null); } public void onLoadFinished(Loader<Cursor> loader, Cursor data) { mAdapter.swapCursor(data); } public void onLoaderReset(Loader<Cursor> loader) { mAdapter.swapCursor(null); } }
What is it!!! I donโt know why no one has ever purchased such a simple example, how to use LoaderManager, CursorLoader and Custom adapter to populate a custom list. In any case, I hope this helps newcomers, like me, in the future.