AlphabetIndexer with Custom Adapter managed by LoaderManager

adapter, android, android-cursorloader, android-loadermanager, simplecursoradapter

Solution

So I finally got this to work. Here's how i did it:

I added:

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

to the `onLoadFinished()` method after the new cursor was swapped in like so

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

}

consequently these three statements were removed from the `onActivityCreated()` method of my custom `ListFragment`.

Problem

I am trying to implement `AlphabetIndexer` with Custom Adapter like this AlphabetIndexer with Custom Adapter My class ContactsCursorAdapter extends `SimpleCursorAdapter` and implements `SectionIndexer` and I am using a `LoaderManager` to manage my adapter's cursor so i have overridden the `swapCursor()` method like the second answer to the example above indicates. ``` 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); } } ``` However, this errors out if I set my listview to fastScrollEnabled = true getListView().setFastScrollEnabled(true); in my class ContactsCursorLoaderListFragment which extends `ListFragment` and implements LoaderManager.LoaderCallbacks . Here is the stack trace: ``` 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 ``` after the `setFastScrollEnabled()` method gets called it calls the custom adapter's `getSections()` method which is where it crashes. ``` 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); } } } ``` And if I comment the `setFastScrollEnabled()` call, then it does not error out, but I do not see the `AlphabetIndexer` working. Does this need to be implemented differently because my custom adapter is set in a `ListFragment` and not a `ListActivity`? Does anyone have suggestions about how to make this all work?

Original source

Related problems