11

he cambiado de un ResourceCursorAdapter donde solía newView y bindView a un SimpleCursorAdapter donde yo estoy usando sólo el método getView.NullPointerException en onLoaderFinished usando SimpleCursorAdapter

Ahora tengo un error en onLoaderFinished. Aunque me da NullPointerException en adapter.swapCursor(cursor) mi adaptador y el cursor son NO nulo. Publicaré todo mi código a continuación. Cualquier ayuda es muy apreciada (no le queda mucho pelo para sacar).

import android.annotation.SuppressLint; 
import android.content.Context; 
import android.database.Cursor; 
import android.net.Uri; 
import android.os.Bundle; 
import android.provider.ContactsContract; 
import android.support.v4.app.FragmentActivity; 
import android.support.v4.app.LoaderManager; 
import android.support.v4.content.CursorLoader; 
import android.support.v4.content.Loader; 
import android.support.v4.widget.ResourceCursorAdapter; 
import android.util.Log; 
import android.util.SparseBooleanArray; 
import android.view.LayoutInflater; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.view.ViewGroup; 
import android.view.Window; 
import android.widget.CheckBox; 
import android.widget.ListView; 
import android.widget.TextView; 

public class ContactSelect extends FragmentActivity implements LoaderManager.LoaderCallbacks<Cursor> { 
private static final int LOADER_ID = 1; 
private MyAdapter adapter; 
private ListView list; 
private View row; 
private SparseBooleanArray checkedState = new SparseBooleanArray(); 

@SuppressLint({ "NewApi", "NewApi" }) 
@Override 
public void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS); 
    setContentView(R.layout.activity_contact_select);  

    adapter = new MyAdapter(this, R.layout.contacts_select_row, null, null, null, 0);  

    getSupportLoaderManager().initLoader(LOADER_ID, null, this);   

    list = (ListView)findViewById(R.id.list);     

    list.setAdapter(adapter); 
    list.setEmptyView(findViewById(R.id.empty));  

} 

@SuppressLint("NewApi") 
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) { 
    final String projection[] = new String[]{ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME}; 
    final Uri uri = ContactsContract.Contacts.CONTENT_URI; 

    final String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1" + 
    " AND " + ContactsContract.Contacts.IN_VISIBLE_GROUP + " =1"; 

    final String order = ContactsContract.Contacts.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; 

    final CursorLoader loader = new CursorLoader(this, uri, projection, selection, null, order); 

    return loader;  
} 

public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) { 
    for(int i=0;i<cursor.getCount();i++){ 
     checkedState.put(i, false); 
    } 

    adapter.swapCursor(cursor);     
} 

public void onLoaderReset(Loader<Cursor> loader) { 
    adapter.swapCursor(null);  
} 

private class MyAdapter extends SimpleCursorAdapter implements OnClickListener{ 
    private CheckBox markedBox; 
    private TextView familyText; 
    private Context context; 
    private Cursor cursor; 

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

     this.context = context; 
     this.cursor = getCursor(); 
    } 

    @Override 
    public View getView(int position, View view, ViewGroup group) { 

     final LayoutInflater li = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
     row = li.inflate(R.layout.contacts_select_row, group, false); 

     view.setTag(cursor.getPosition()); 
     view.setOnClickListener(this); 

     familyText = (TextView)view.findViewById(R.id.contacts_row_family_name); 
     markedBox = (CheckBox)view.findViewById(R.id.contacts_row_check); 
     familyText.setText(cursor.getString(cursor.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME))); 

     boolean currentlyChecked = checkedState.get(cursor.getPosition()); 
     markedBox.setChecked(currentlyChecked);  


     setProgressBarIndeterminateVisibility(false); 

     return super.getView(position, view, group); 
    } 

    public void onClick(View view) { 
     int rowId = (Integer)view.getTag(); 
     Log.d("OnClick", String.valueOf(rowId)); 
     boolean currentlyChecked = checkedState.get(rowId); 
     markedBox.setChecked(!currentlyChecked); 
     checkedState.put(rowId, !currentlyChecked); 
     Log.d("checkedState", "checkedState(" + rowId + ") = " + checkedState.get(rowId)); 
    }  
     }  
} 
+0

proporcione su extracto de importación porque el paquete del Cursor exacto está impreso o no –

+0

He agregado mis importaciones a la pregunta original – Stephen

+3

¿Se puede publicar el logcat también? Solo necesito saber si la pila termina en el punto que mencionaste o va más allá – nandeesh

Respuesta

12

Una llamada del método de la clase SimpleCursorAdapterswapCursor dará lugar a una función que mapea los nombres de las columnas de la matriz String proporcionado al constructor (el cuarto parámetro) a una matriz de enteros que representa los índices de las columnas. A medida que pasan null en el constructor de MyAdapter para la matriz String que representa los nombres de columnas desde el cursor, esto va a lanzar una NullPointerException más tarde cuando el swapCursor a tratar de hacer el mapeo (el NullPointerException debe aparecer en un método findColumns, que es el actual método que utiliza los nombres de columna String matriz).

La solución es pasar un String gama válida, es posible que también desee hacer esto para la matriz que representa int las identificaciones de los puntos de vista en el que colocar los datos:

String[] from = {ContactsContract.Contacts.DISPLAY_NAME}; 
int[] to = {R.id.contacts_row_family_name, R.id.contacts_row_check}; 
adapter = new MyAdapter(this, R.layout.contacts_select_row, null, from, to, 0); 

no sé lo que está intentando hacer pero su implementación del método getView no es correcta:

Hace lo normal para el método getView (creando diseños, buscando vistas, datos de enlace) y luego simplemente devuelve la vista del superclase (?!?), probablemente solo verá el valor predeterminado diseño sin nada.

La forma en que escribió el método getView no es muy eficiente, es posible que desee examinar el reciclaje de vistas y el patrón del titular de la vista.

No haga lo que quiera porque no mueve el cursor a la posición correcta. De forma predeterminada, los adaptadores basados ​​en cursores lo harán por usted en el método getView, pero, a medida que anula el método, su trabajo es mover la posición del cursor.

debe abandonar el método getView y utilizar los dos métodos newView y bindView, ya que ofrecen una mejor separación de la lógica.

2

adaptador = new MyAdapter (esto, R.layout.contacts_select_row, null, null, null, 0);

y su clase MyAdapter está de paso de cursor nulo

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

     this.context = context; 
     this.cursor = getCursor(); 
    } 
+0

Hola, gracias por responder. El motivo del paso del cursor nulo se debe a que no tendré un objeto de cursor hasta que termine el LoaderManager.Debo señalar que este código funcionó perfectamente bien durante el uso de ResourceCursorAdapter – Stephen

Cuestiones relacionadas