带有由LoaderManager管理的自定义适配器的AlphabetIndexer

时间:2012-04-19 08:22:57

标签: android adapter simplecursoradapter android-cursorloader android-loadermanager

我正在尝试使用自定义适配器实现AlphabetIndexer

AlphabetIndexer with Custom Adapter

我的班级ContactsCursorAdapter扩展SimpleCursorAdapter并实施SectionIndexer 我使用LoaderManager来管理我的适配器光标,所以我已经覆盖了swapCursor()方法,就像上面示例的第二个答案所示。

public class ContactsCursorAdapter extends SimpleCursorAdapter 
    implements SectionIndexer{

    private LayoutInflater mInflater;
    private Context mContext; 

    private AlphabetIndexer mAlphaIndexer;

    public ContactsCursorAdapter(Context context, int layout, Cursor c,
        String[] from, int[] to) {
        super(context, layout, c, from, to);

        mInflater = LayoutInflater.from(context);
        mContext = context;
    }

    public View getView(final int position, View convertView, ViewGroup parent) {
        ...
    }

    @Override
    public int getPositionForSection(int section) {
        return mAlphaIndexer.getPositionForSection(section);
    }

    @Override
    public int getSectionForPosition(int position) {
        return mAlphaIndexer.getSectionForPosition(position);
    }

    @Override
    public Object[] getSections() {
        return mAlphaIndexer.getSections();
    }

    public Cursor swapCursor(Cursor c) {
        // Create our indexer
        if (c != null) {
            mAlphaIndexer = new AlphabetIndexer(c, c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME),
                " ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        }
        return super.swapCursor(c);
    }
}

但是,如果我将listview设置为fastScrollEnabled = true

,则会出错

getListView()setFastScrollEnabled(真)。

在我的类ContactsCursorLoaderListFragment中,它扩展了ListFragment并实现了LoaderManager.LoaderCallbacks。

这是堆栈跟踪:

04-25 01:37:23.280: E/AndroidRuntime(711): FATAL EXCEPTION: main
04-25 01:37:23.280: E/AndroidRuntime(711): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.sendit/com.sendit.ContactManager}: java.lang.NullPointerException
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1956)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:1981)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.app.ActivityThread.access$600(ActivityThread.java:123)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1147)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.os.Handler.dispatchMessage(Handler.java:99)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.os.Looper.loop(Looper.java:137)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.app.ActivityThread.main(ActivityThread.java:4424)
04-25 01:37:23.280: E/AndroidRuntime(711):  at java.lang.reflect.Method.invokeNative(Native Method)
04-25 01:37:23.280: E/AndroidRuntime(711):  at java.lang.reflect.Method.invoke(Method.java:511)
04-25 01:37:23.280: E/AndroidRuntime(711):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784)
04-25 01:37:23.280: E/AndroidRuntime(711):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551)
04-25 01:37:23.280: E/AndroidRuntime(711):  at dalvik.system.NativeStart.main(Native Method)
04-25 01:37:23.280: E/AndroidRuntime(711): Caused by: java.lang.NullPointerException
04-25 01:37:23.280: E/AndroidRuntime(711):  at com.sendit.ContactsCursorAdapter.getSections(ContactsCursorAdapter.java:222)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.widget.FastScroller.getSectionsFromIndexer(FastScroller.java:507)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.widget.FastScroller.init(FastScroller.java:269)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.widget.FastScroller.<init>(FastScroller.java:155)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.widget.AbsListView.setFastScrollEnabled(AbsListView.java:1144)
04-25 01:37:23.280: E/AndroidRuntime(711):  at com.sendit.LoaderCursor$ContactsCursorLoaderListFragment.onActivityCreated(LoaderCursor.java:107)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:847)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1032)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.app.BackStackRecord.run(BackStackRecord.java:622)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1382)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.app.Activity.performStart(Activity.java:4474)
04-25 01:37:23.280: E/AndroidRuntime(711):  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:1929)
04-25 01:37:23.280: E/AndroidRuntime(711):  ... 11 more

setFastScrollEnabled()方法被调用之后,它调用自定义适配器的getSections()方法,它就是崩溃的地方。

public class LoaderCursor extends Activity {

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

        FragmentManager fm = getFragmentManager();

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

    public static class ContactsCursorLoaderListFragment extends ListFragment
        implements LoaderManager.LoaderCallbacks<Cursor> {

        ContactsCursorAdapter mAdapter;
        Cursor mCursor;
        String mCurFilter;

        @Override
        public void onActivityCreated(Bundle savedInstanceState) {
            super.onActivityCreated(savedInstanceState);

            populateContactList();

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

            ListView lv = getListView();
            lv.setFastScrollEnabled(true);
            //lv.setScrollingCacheEnabled(true);
            lv.setDivider(getResources().getDrawable(R.drawable.list_divider));

        }       

        // These are the Contacts rows that we will retrieve.
        final String[] CONTACTS_SUMMARY_PROJECTION = new String[] {
            ContactsContract.Contacts._ID,
            ContactsContract.Contacts.DISPLAY_NAME,
            ContactsContract.Contacts.PHOTO_ID, };

        public Loader<Cursor> onCreateLoader(int id, Bundle args) {
            // This is called when a new Loader needs to be created. This
            // sample only has one Loader, so we don't care about the ID.
            // First, pick the base URI to use depending on whether we are
            // currently filtering.
            Uri baseUri;
            if (mCurFilter != null) {
                baseUri = Uri.withAppendedPath(ContactsContract.Contacts.CONTENT_FILTER_URI,Uri.encode(mCurFilter));
            } else {
                baseUri = ContactsContract.Contacts.CONTENT_URI;
            }

            // Now create and return a CursorLoader that will take care of
            // creating a Cursor for the data being displayed.
            String selection = "((" + ContactsContract.Contacts.DISPLAY_NAME + 
                " NOTNULL) AND (" + ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1) 
                AND (" + ContactsContract.Contacts.DISPLAY_NAME + " != '' ))";
            String sortOrder = ContactsContract.Contacts.DISPLAY_NAME
                + " COLLATE LOCALIZED ASC";

            return new CursorLoader(getActivity(), baseUri,
                CONTACTS_SUMMARY_PROJECTION, selection, null, sortOrder);

        }

        public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
            // Swap the new cursor in.  (The framework will take care of closing the
            // old cursor once we return.)
            mAdapter.swapCursor(data);
        }

        public void onLoaderReset(Loader<Cursor> loader) {
            // This is called when the last Cursor provided to onLoadFinished()
            // above is about to be closed. We need to make sure we are no
            // longer using it.
            mAdapter.swapCursor(null);
        }

        /**
        * Populate the contact list
        */
        private void populateContactList() {

            // start mappings
            String[] from = new String[] { ContactsContract.Contacts.DISPLAY_NAME };
            int[] to = new int[] { R.id.contactInfo };

            // Create an empty adapter we will use to display the loaded data.
            mAdapter = new ContactsCursorAdapter(getActivity().getApplicationContext(),    
                R.layout.contact_manager, null, from, to);
            setListAdapter(mAdapter);
        }   

    }
}

如果我对setFastScrollEnabled()来电发表评论,那么它就不会出错,但我看不到AlphabetIndexer正在发挥作用。

这是否需要以不同的方式实现,因为我的自定义适配器是在ListFragment而不是ListActivity中设置的?

有没有人有关于如何使这一切工作的建议?

1 个答案:

答案 0 :(得分:9)

所以我终于开始工作了。我是这样做的:

我补充说:

ListView lv = getListView();
lv.setFastScrollEnabled(true);
lv.setScrollingCacheEnabled(true);
新光标交换后,

onLoadFinished()方法

public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
 // Swap the new cursor in.  (The framework will take care of closing the
 // old cursor once we return.)
 mAdapter.swapCursor(data);

 ListView lv = getListView();
 lv.setFastScrollEnabled(true);
 lv.setScrollingCacheEnabled(true);

}

因此,这三个语句已从我的自定义onActivityCreated()的{​​{1}}方法中删除。