【问题标题】:Display Album and Artist in listview with LoaderManager and CursorLoader使用 LoaderManager 和 CursorLoader 在列表视图中显示专辑和艺术家
【发布时间】:2012-06-14 17:23:20
【问题描述】:

我有一个ListFragment,其列表应显示设备的专辑和使用MediaStore 的关联艺术家。因此,每行有两个TextViews。 我使用LoaderManagerCursorLoader 来填充列表,并使用自定义CursorAdapter 将行的TextViews 绑定到数据。

列表片段代码:

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(自定义CursorAdapter)代码:

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;
    }

目前,当我显示这个 ListFragment 时,我有一个 java.lang.NullPointerException,这里是 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)

您能帮我更正我的代码,以便将专辑和相关艺术家显示到列表视图中吗?

问题已解决:

对于任何尝试使用 LoaderManager/CursorLoader 技术填充自定义列表视图的人来说,您应该:

1) 创建您自己的自定义 CursorAdapter,它将您的行的 TextViews 绑定到光标的数据(请参阅上面的自定义 CursorAdapter)

2) 然后,在您的片段中执行以下操作:

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);  
        }  
    }

就是这样!我不知道为什么没有人购买过这样一个关于如何使用 LoaderManager、CursorLoader 和自定义适配器来填充自定义列表视图的非常简单的示例。无论如何,我希望这对以后像我这样的初学者有所帮助。

【问题讨论】:

  • 当您遇到异常(NullPointerException 或任何异常)时,您应该始终显示引发该异常的行。
  • @Luksprog :感谢您的精确,我已经更新了我的帖子。例外似乎在第 61 行,那里有mAdapter.swapCursor(data);。也许我查询MediaStore 的方式有问题,所以data 为空导致此异常?
  • 嘿@Jecimi 如果您不介意,我有几个问题。我也在尝试用 LoaderManager 和 CursorLoader 制作 CursorAdapter。除了我从数据库中获取游标。我也没有使用 ListFragment,而只是一个常规列表。所以这意味着我的列表在一个带有另一个视图的活动中,实际上是一个 GridView。如何设置它以使用 LoaderManager 和 CursorLoader 而无需更改我当前的布局?
  • @Andy:如果您的布局中只有一个ListView,其他视图属于其他类型,我认为最简单的方法是将您的Activity 转换为ListActivity。即使是ListActivity,也不意味着你必须强制只有一个ListView,这只是意味着你的活动包含一个ListView。看看我上面的ListFragment,我确实夸大了它使用我的 XML albums_fragment_layout.xml,它不仅包含一个 ListView,还包含其他视图。您只需将android:id="@id/android:list 设置为ListView,然后像ListFragment 一样使用ListActivity
  • +1 感谢您的分享解决方案。效果很好。

标签: android android-listfragment android-music-player android-cursorloader


【解决方案1】:

我认为您的 mAdapternull(如果您初始化了它,我看不到您在哪里初始化它)并且当您尝试交换光标时它会引发该异常。

如果您没有初始化 AlbumAdapter 引用,那么您应该在设置适配器之前进行初始化:

mAdapter = new AlbumsAdapter(getActivity(), null);
setListAdapter(mAdapter);

【讨论】:

  • 谢谢!!!缺少两件事:我忘记按照您所说的初始化自定义适配器,并且忘记将 MediaStore.Audio.Albums._ID 放入我的投影中。
猜你喜欢
  • 2012-02-15
  • 1970-01-01
  • 1970-01-01
  • 2013-06-02
  • 1970-01-01
  • 2013-01-24
  • 2013-10-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多