11

Ich versuche AlphabetIndexer mit benutzerdefinierten Adapter wie dieseAlphabetIndexer mit benutzerdefinierten Adapter verwaltet von LoaderManager

AlphabetIndexer with Custom Adapter

Meine Klasse ContactsCursorAdapter SimpleCursorAdapter erweitert zu implementieren und implementiert SectionIndexer und ich bin mit einem LoaderManager mein Adapters Cursor verwalten also habe ich die swapCursor() methode wie die zweite antwort auf das obige Beispiel überschrieben.

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

Doch diese Fehler, wenn ich mein Listview fastScrollEnabled = true

getListView() setFastScrollEnabled (true).

in meiner Klasse ContactsCursorLoaderListFragment, die ListFragment erweitert und implementiert LoaderManager.LoaderCallbacks. Hier

ist der 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 

nach dem setFastScrollEnabled() Methode aufgerufen wird, ruft es die getSections() Methode des benutzerdefinierten Adapter das ist, wo es stürzt ab.

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

    } 
} 

Und wenn ich den setFastScrollEnabled() Anruf kommentieren, dann ist es nicht Fehler aus, aber ich sehe nicht die AlphabetIndexer Arbeiten.

Muss dies anders implementiert werden, weil mein benutzerdefinierter Adapter in eine ListFragment und nicht eine ListActivity eingestellt ist?

Hat jemand Vorschläge, wie das alles funktioniert?

Antwort

9

Also habe ich das endlich zur Arbeit gebracht. Hier ist, wie ich es tat:

ich hinzugefügt:

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

zum onLoadFinished() Verfahren nach dem neuen Cursor getauscht wurde wie 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); 

} 

folglich diese drei Aussagen aus dem onActivityCreated() Verfahren entfernt wurden von meiner Gewohnheit ListFragment.

+0

Guter Fang. Vielen Dank. – nobre

+0

Wäre es nicht besser, wenn Ihre 'getSections'-Methode eine leere Liste zurückgibt, wenn keine Daten vorhanden sind, anstatt eine Nullzeiger-Ausnahme auszulösen? –

+0

Ja, es wäre eine gute Idee, eine leere Liste zurückzugeben, wenn die Daten nicht verfügbar sind, aber die getSections() sollten aufgerufen werden, nachdem der Cursor eingelagert wurde, da dies einen CursorLoader implementiert. – toobsco42