title: IllegalStateException: attempt to re-open an already-closed object
body: <p>I'm using <code>Cursor</code> inside a retained <code>DialogFragment</code>. The <code>Cursor</code> is loaded by <code>AsyncTask</code> after the <code>DialogFragment</code>'s view is created and is closed when <code>DialogFragment</code> gets destroyed. Then the <code>Cursor</code> will be handed to a <code>SimpleCursorAdapter</code>.</p>
  
  <p>Currently I'm testing on Froyo emulator. Problem is, when I scrolled fastly on the <code>ListView</code> -> dismissed the dialog -> opened it again -> the app crashed (see Log below).</p>
  
  <p>I have not encountered similar problem when on my phone and there is no problem either when I wait for the <code>ListView</code> to stop scrolling before closing the dialog and opening it again.</p>
  
  <p>Logcat:</p>
  
  <pre><code>07-15 22:09:45.402: E/AndroidRuntime(494): FATAL EXCEPTION: main
  07-15 22:09:45.402: E/AndroidRuntime(494): java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.sqlite.SQLiteQuery (mSql = my query) 
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.database.sqlite.SQLiteClosable.acquireReference(SQLiteClosable.java:34)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.database.sqlite.SQLiteQuery.fillWindow(SQLiteQuery.java:64)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.database.sqlite.SQLiteCursor.fillWindow(SQLiteCursor.java:283)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.database.sqlite.SQLiteCursor.onMove(SQLiteCursor.java:255)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.database.AbstractCursor.moveToPosition(AbstractCursor.java:188)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.support.v4.widget.CursorAdapter.getView(CursorAdapter.java:247)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.widget.AbsListView.obtainView(AbsListView.java:1294)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.widget.ListView.makeAndAddView(ListView.java:1727)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.widget.ListView.fillDown(ListView.java:652)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.widget.ListView.fillGap(ListView.java:623)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.widget.AbsListView.trackMotionScroll(AbsListView.java:2944)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.widget.AbsListView$FlingRunnable.run(AbsListView.java:2485)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.os.Handler.handleCallback(Handler.java:587)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.os.Handler.dispatchMessage(Handler.java:92)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.os.Looper.loop(Looper.java:123)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at android.app.ActivityThread.main(ActivityThread.java:4627)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at java.lang.reflect.Method.invokeNative(Native Method)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at java.lang.reflect.Method.invoke(Method.java:521)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:868)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:626)
  07-15 22:09:45.402: E/AndroidRuntime(494):  at dalvik.system.NativeStart.main(Native Method)
  </code></pre>
  
  <p>DialogFragment:</p>
  
  <pre><code>public class SearchAirportFragment extends DialogFragment {
      private Activity mContext;
      private SimpleCursorAdapter adapter;
      private Cursor cursor = null;
      private LoadCursor taskLoad;
  
      public static DialogFragment newInstance(int jenisPenerbangan) {
          DialogFragment f = new SearchAirportFragment();
          f.setRetainInstance(true);
          return f;
      }
  
      @Override
      public void onAttach(Activity activity) {
          super.onAttach(activity);
          mContext = activity;
      }
  
      @Override
      public void onDetach() {
          mContext = null;
          super.onDetach();
      }
  
      @Override
      public void onDestroy() {
          if (taskLoad != null)
              taskLoad.cancel(false);
  
          if (cursor != null) {
              cursor.close();
          }
          super.onDestroy();
      }
  
  
      @Override
      public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          View view = inflater.inflate(R.layout.fragment_search_airport, container, false);
          ListView listView = (ListView) view.findViewById(R.id.listView1);
          adapter = new SimpleCursorAdapter(mContext, R.layout.list_item_text, cursor, new String[] { "name" }, new int[] { R.id.text1 }, 0);
          listView.setAdapter(adapter);
          if (cursor == null &amp;&amp; taskLoad == null) {
              taskLoad = new LoadCursor(this, 1, "test");
              taskLoad.execute();
          }
          return view;
      }
  
      @Override
      public void onDestroyView() {
          adapter = null;
          Dialog d = getDialog();
          if (d != null &amp;&amp; getRetainInstance())
              d.setDismissMessage(null);
          super.onDestroyView();
      }
  
      public void updateCursor(Cursor result) {
          cursor = result;
          if (adapter != null) {
              adapter.changeCursor(cursor);
          }
      }
  
  
      private static class LoadCursor extends AsyncTask&lt;Void, Void, Cursor&gt; {
          private String keyword;
          private WeakReference&lt;SearchAirportFragment&gt; fragmentReference;
  
          public LoadCursor(SearchAirportFragment fragment, int myflag,
              String search) {
              this.keyword = search;
              this.fragmentReference = new WeakReference&lt;SearchAirportFragment&gt;(fragment);
          }
  
          @Override
          protected Cursor doInBackground(Void... params) {
              DatabaseHelper dbHelper = DatabaseHelper.getInstance(MyApplication.getContext());
              SQLiteDatabase db = dbHelper.getReadableDatabase();
              Cursor c = /* my query */;
              return c;
          }
  
          @Override
          protected void onCancelled(Cursor result) {
              if (result != null) result.close();
          }
  
          @Override
          protected void onPostExecute(Cursor result) {
              SearchAirportFragment f = fragmentReference.get();
              if (f != null &amp;&amp; result != null) {
                  f.updateCursor(result);
              }
          }
      }
  }
  </code></pre>
  
  <p><strong>UPDATE</strong></p>
  
  <p>Maybe somehow <code>ListView</code> still gets scrolled (therefore adapter's <code>getView()</code> is called) after it's destroyed.</p>
  
  <p>This solves it:</p>
  
  <pre><code>@Override
  public void onDestroyView() {
      adapter.swapCursor(null);
      adapter = null;
      Dialog d = getDialog();
      if (d != null &amp;&amp; getRetainInstance())
          d.setDismissMessage(null);
      super.onDestroyView();
  }
  </code></pre>