11

Estoy tratando de poner en práctica AlphabetIndexer con adaptador personalizado como ésteAlphabetIndexer con adaptador personalizado administrado por LoaderManager

AlphabetIndexer with Custom Adapter

Mi ContactsCursorAdapter clase extiende SimpleCursorAdapter e implementa SectionIndexer y estoy usando un LoaderManager para manejar el cursor de mi adaptador así que he anulado el método swapCursor() como lo indica la segunda respuesta al ejemplo anterior.

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

Sin embargo, esta errores hacia fuera si fijo mi vista de lista a fastScrollEnabled = true

getListView() setFastScrollEnabled (verdadero).;

en mi clase ContactsCursorLoaderListFragment que extiende ListFragment e implementa LoaderManager.LoaderCallbacks.

Aquí es el seguimiento de la pila:

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 

después del método setFastScrollEnabled() se llama que llama el método del adaptador personalizado getSections() que es donde se bloquea.

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

    } 
} 

Y si comento la llamada setFastScrollEnabled(), entonces no tiene error, pero no veo el trabajo AlphabetIndexer.

¿Es necesario implementar esto de manera diferente porque mi adaptador personalizado está configurado en ListFragment y no en ListActivity?

¿Alguien tiene alguna sugerencia sobre cómo hacer que todo esto funcione?

Respuesta

9

Así que finalmente conseguí que esto funcione. Así es como lo hice:

añadí:

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

al método onLoadFinished() después de que el nuevo cursor se cambió de igual modo

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

} 

en consecuencia, estas tres declaraciones fueron retirados del método onActivityCreated() de mi personalizado ListFragment.

+0

Buena captura. Gracias. – nobre

+0

¿No sería mejor hacer que su método 'getSections' devuelva una lista vacía si no hay datos en lugar de arrojar una excepción de puntero nulo? –

+0

Sí, sería una buena idea devolver una lista vacía si los datos no están disponibles; sin embargo, debe llamarse a getSections() después de que se haya intercambiado el cursor, ya que esto está implementando un CursorLoader. – toobsco42

Cuestiones relacionadas