问题
I have a ListFragment
whose list should diplay the Albums of the device and the associated artist using MediaStore
. Each row has thus two TextViews
.
I'm using LoaderManager
and CursorLoader
to fill the list up, with a custom CursorAdapter in order to bind the TextViews
of the row to the data.
ListFragment 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;
}
For the moment, when I display this ListFragment, I have a java.lang.NullPointerException, here is the 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 please help me to correct my code in order to have the album and the associated artist displayed into the listview ?
Problem Solved :
For anyone trying to fill up a custom listview with Album,Artist,etc... with the technique LoaderManager/CursorLoader you should :
1) Create your own Custom CursorAdapter which binds TextViews of your row to Cursor's data(see my Custom CursorAdapter above)
2) Then, in your fragment here's 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);
}
}
And that's it !!! I don't know why nobody has ever procured a very simple example like this about how to use LoaderManager,CursorLoader and Custom adapter in order to fill a custom listview. Anyway, I hope this will help beginners like me in the future.
回答1:
I think your mAdapter
is null
(I don't see where you initialized it, if you initialized it) and when you try to swap the cursor it throws that exception.
if you didn't initialized that AlbumAdapter
reference then you should do it before you set the adapter:
mAdapter = new AlbumsAdapter(getActivity(), null);
setListAdapter(mAdapter);
来源:https://stackoverflow.com/questions/11025350/display-album-and-artist-in-listview-with-loadermanager-and-cursorloader