26

Así que tengo mi MainDisplayActivity que implementa tanto Activity como LoaderManager.LoaderCallbacks<Cursor>. Aquí tengo A ListView, que llené con la información de la Agenda que obtengo de mi base de datos usando ContentProvider. También tengo un GridView que es un calendario. Lo tengo configurado al hacer clic en una celda, que la agenda se actualiza con el día en que se hace clic. Mi problema es que al reutilizar el Loader que creé en onCreate() dentro de setOnItemClickListener(), no actualiza la información con el nuevo cursor que estoy creando. Puedo simplemente crear un nuevo cargador con otro ID, y funciona una vez, pero una vez que hago clic en otro día, deja de refrescarse. El problema, se encuentra en el cursor. ¿Cómo puedo actualizar un cursor desde un cargador para no tener que seguir creando un nuevo cargador? ¡Gracias por adelantado!¿Cómo puedo actualizar el cursor desde un CursorLoader?

llamada inicial para crear el cargador en onCreate() en mi clase MainDisplayActivity:

makeProviderBundle(new String[] {"_id, event_name, start_date, start_time, end_date, end_time, location"}, 
      "date(?) >= start_date and date(?) <= end_date", new String[]{getChosenDate(), getChosenDate()}, null); 
    getLoaderManager().initLoader(0, myBundle, MainDisplayActivity.this); 

    list.setAdapter(agendaAdapter); 

Estos son los métodos sobrescritos de LoaderCallbacks<Cursor>

@Override 
public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
    Uri baseUri = SmartCalProvider.CONTENT_URI; 
    return new CursorLoader(this, baseUri, args.getStringArray("projection"), 
      args.getString("selection"), args.getStringArray("selectionArgs"), args.getBoolean("sortOrder") ? args.getString("sortOrder") : null); 
} 



@Override 
public void onLoadFinished(Loader<Cursor> arg0, Cursor arg1) { 
    agendaAdapter.swapCursor(arg1); 
} 



@Override 
public void onLoaderReset(Loader<Cursor> arg0) { 
    //Not really sure how this works. Maybe I need to fix this here? 
    agendaAdapter.swapCursor(null); 

} 

public void makeProviderBundle(String[] projection, String selection, String[] selectionArgs, String sortOrder){ 
    /*this is a convenience method to pass it arguments 
    * to pass into myBundle which in turn is passed 
    * into the Cursor loader to query the smartcal.db*/ 
    myBundle = new Bundle(); 
    myBundle.putStringArray("projection", projection); 
    myBundle.putString("selection", selection); 
    myBundle.putStringArray("selectionArgs", selectionArgs); 
    if(sortOrder != null) myBundle.putString("sortOrder", sortOrder); 
} 

Cualquier código adicional necesario por favor, no dude en preguntar . Gracias de nuevo por cualquier ayuda!

+0

Según mi experiencia, cuando usas 'ContentResolver' para actualizar un contenido en' ContentProvider', el 'cursor' se notifica y la lista se actualiza automáticamente. ¿Podría publicar su código onClick también? – stuckless

+0

Sé bien. Asumí esto también, ya que todos decían qué conveniente era eso. Pero eso no hace eso. El problema es que también entiendo cómo eso no puede funcionar. Cuando se crea el 'Loader' por primera vez, llama a' onCreateLoader() '. Al llamar a 'getLoaderManager(). InitLoader()', si el primer arg, el ID es lo mismo que un 'Loader' previamente instanciado,' onCreateLoader() 'probablemente no se invocará. Por supuesto, esto es pura especulación de mi parte, ya que todavía estoy aprendiendo, pero pensé que tenía que haber un método para cargar un nuevo Cursor si ese fuera el caso. Alex fue lo suficientemente bueno para proporcionarlo! – Andy

Respuesta

40

Solo tiene que mover su código un poco y llamar al restartLoader. Es decir,

  1. Cuando el usuario hace clic en un elemento de la lista, que de alguna manera cambia la variable de instancia privada que se devuelve en getChosenDate() (estoy siendo deliberadamente vaga aquí porque no se especificó qué es exactamente getChosenDate() devoluciones).

  2. Una vez realizado el cambio, llame al getLoaderManager().restartLoader() en su Loader. Los datos anteriores se descartarán y restartLoader activará onCreateLoader para que se vuelva a llamar. Esta vez, getChosenDate() devolverá un valor diferente (dependiendo del elemento de la lista en el que se hizo clic) y eso debería hacerlo. Su aplicación onCreateLoader debería ser algo como esto:

    @Override 
    public Loader<Cursor> onCreateLoader(int id, Bundle args) { 
        Uri baseUri = SmartCalProvider.CONTENT_URI; 
    
        makeProviderBundle(
         new String[] { "_id, event_name, start_date, start_time, end_date, end_time, location" }, 
         "date(?) >= start_date and date(?) <= end_date", 
         new String[]{ getChosenDate(), getChosenDate() }, 
         null); 
    
        return new CursorLoader(
          this, 
          baseUri, 
          args.getStringArray("projection"), 
          args.getString("selection"), 
          args.getStringArray("selectionArgs"),  
          args.getBoolean("sortOrder") ? args.getString("sortOrder") : null); 
    } 
    

Quiero saber si eso tiene sentido. :)

+0

Holy shiznit lol. Eso es genio jaja. Veo lo que dices. Entonces el método que podría llamar es 'restartLoader()'. ¿Cómo es que no veo ese método en CursorLoader? Ah, y lo siento, 'getChosenDate()' devuelve una fecha de cadena en el formato utilizado por las bases de datos, así que puedo hacer todo el filtrado con SQLite en lugar de hacerlo con código Java. – Andy

+0

¡Tío! ¡Te amo! Funcionó maravillosamente. Y mirando mi código me di cuenta en 'myBundle.putString (" date ", getChosenDate());', no era necesario. Entonces me lo quité. Voy a usarlo cuando llame 'makeProviderBundle()'. ¡Muchas gracias de nuevo! – Andy

+11

Jaja ... usted es fácilmente excitable, ¿verdad? Me alegro de poder ayudar :). –

Cuestiones relacionadas