2010-06-08 1 views
5

Nella mia applicazione, dopo abbastanza clic in giro, ottengo questo errore:StaleDataException: accesso chiuso cursore

06-08 19:47:59.967: ERROR/AndroidRuntime(2429): java.lang.RuntimeException: Unable to pause activity {com.MYAPP.app/com.MYAPP.app.MainActivity}: android.database.StaleDataException: Access closed cursor 

Quello che ho è una scheda di attività (il mio MainActivity), che ha un ListActivity come il contenuto di ogni scheda. All'interno di onCreate per ogni ListActivity viene visualizzato un cursore che rappresenta i dati da visualizzare in tale elenco.

L'onListItemClick per ogni elenco crea anche un'altra attività, quindi facendo clic su un elemento nell'elenco verranno visualizzate ulteriori informazioni su quell'elemento in una nuova schermata. È incoerente, ma dopo aver fatto abbastanza clic su queste nuove attività o tornare a ListView da una nuova attività, il programma si arresta in modo anomalo.

Nel cercare una soluzione al mio problema, mi sono imbattuto in registerDataSetObserver, ma non sembra essere l'intera risposta. Ho anche difficoltà a trovare la documentazione su di esso, quindi non sono sicuro di averlo capito appieno. Ho un ListAdapter personalizzato che entrambi i miei ListViews utilizzano e hanno chiamato registerDataSetObservers sui cursori lì.

Ho allegato il codice pertinente da uno dei miei ListActivities e dalla mia classe ListAdapter personalizzata.


ListActivity. Ho due di questi, quasi identico, tranne che entrambi hanno diversi cursori creati da diverse query di database:

import com.MYAPP.app.listmanager.DeviceListAdapter; 

public class AllSensorsActivity extends ListActivity{ 

    private DeviceListAdapter AllList; 
    private DbManager db; 
    protected Cursor AllCur; 
    protected Cursor AllSensors; 


    private static final String TAG = "AllSensorsActivity";      

    @Override 
    public void onCreate(Bundle savedInstanceState){ 
     super.onCreate(savedInstanceState); 
     Log.e(TAG, "Calling All onCreate"); 

     db = new DbManager(this); 
     db.open(); 

     AllCur = db.fetchAllDevices(); 
     startManagingCursor(AllCur);            
     AllSensors = db.fetchAllSensors(); 
     startManagingCursor(AllSensors); 


     AllList = new DeviceListAdapter(this, AllCur, AllSensors); 
     setListAdapter(AllList); 
    } 


    @Override 
    protected void onListItemClick(ListView l, View v, int position, long id){ 

     String device_name = (String) ((DeviceListAdapter)getListAdapter()).getItem(position); 
     String sensor_string = ((DeviceListAdapter)getListAdapter()).getSensors(id); 

     Intent i = new Intent(this, SensorActivity.class); 
     Bundle bundle = new Bundle(); 
     bundle.putString("NAME", device_name); 
     i.putExtras(bundle); 
     bundle.putString("SENSORS", sensor_string); 
     i.putExtras(bundle); 
     this.startActivity(i); 

    } 

Il ListAdapter personalizzato:

public class DeviceListAdapter extends BaseAdapter { 

    private static final String TAG = "DeviceListAdapter"; 

    private Context mContext; 
    private Cursor mSensors; 
    private Cursor mDevices; 
    protected MyDataSetObserver sensors_observer; 
    protected MyDataSetObserver devices_observer; 

    public DeviceListAdapter(Context context, Cursor devices, Cursor sensors){ 
     mContext = context; 
     mDevices = devices; 
     mSensors = sensors; 

     sensors_observer = new MyDataSetObserver(); 
     mSensors.registerDataSetObserver(sensors_observer); 
     devices_observer = new MyDataSetObserver(); 
     mDevices.registerDataSetObserver(devices_observer); 
    } 
    // ... more functions and stuff that are not relevant go down here... 
} 

private class MyDataSetObserver extends DataSetObserver { 
    public void onChanged(){ 
     Log.e(TAG, "CHANGED CURSOR!"); 
    } 
    public void onInvalidated(){ 
     Log.e(TAG, "INVALIDATED CURSOR!"); 
    } 
} 

devo solo avere MyDataSetObserver intercettare l'eccezione e andare avanti ? Mi piacerebbe una soluzione più robusta di quella, se possibile. O c'è un altro modo in cui posso riorganizzare il mio programma in modo che staleDataException non si verifichi (come spesso)? Credo che stia accadendo perché sto lanciando la nuova attività nel mio onListItemClick.

risposta

6

Credo che quando viene invalidato, si desidera chiamare requery() sul cursore. Potresti farlo in onInvalidated().

+1

Quando ho inserito cursor.requery() in onInvalidated(), non ho potuto bloccarlo, non importa quanto ci provassi. Horray! Ma penso che startManagingCursor() si occuperà delle richieste per me - è perché ho messo in pausa l'attività in cui viene chiamato startManagingCursor()? – Aurora

+0

Non sono sicuro, ma se lo desideri potresti probabilmente trovare dove viene invalidato stampando una traccia stack in onInvalidated. La domanda –

+4

è deprecata http://developer.android.com/reference/android/database/Cursor.html#requery() – AndroidGecko