title: swapCursor() slow: "The application may be doing too much work on its main thread."
body: <p>I keep seeing "The application may be doing too much work on its main thread."</p>
  
  <p>Is this being caused by swapCursor() in my code below? It appears so: if I remove it, the above  warning disappears.</p>
  
  <p>I still don't understand why it claims to be the main thread that is causing the problem. I have moved the swapCursor() around into various places such as onLoadFinished() and in loadInBackground() but I get the same result.</p>
  
  <p>How can I call swapCursor() so that this warning doesn't appear? The whole reason I used SimpleCursorLoader was avoid holding up the main thread but its still happening.</p>
  
  <pre><code>package com.example.sqlitetest;
  
  import java.util.ArrayList;
  import java.util.HashMap;
  import java.util.List;
  
  import android.app.Activity;
  import android.content.Context;
  import android.database.Cursor;
  import android.database.sqlite.SQLiteDatabase;
  import android.os.Bundle;
  import android.support.v4.app.FragmentActivity;
  import android.support.v4.app.LoaderManager;
  import android.support.v4.app.LoaderManager.LoaderCallbacks;
  import android.support.v4.content.Loader;
  import android.support.v4.content.CursorLoader;
  import android.support.v4.widget.SimpleCursorAdapter;
  import android.support.v4.widget.SimpleCursorAdapter.ViewBinder;
  import android.view.Gravity;
  import android.view.MotionEvent;
  import android.view.View;
  import android.view.View.OnTouchListener;
  import android.view.ViewGroup;
  import android.widget.AbsListView;
  import android.widget.AdapterView;
  import android.widget.ImageView;
  import android.widget.LinearLayout;
  import android.widget.LinearLayout.LayoutParams;
  import android.widget.ListView;
  import android.widget.TextView;
  
  public class MainActivity extends FragmentActivity implements LoaderManager.LoaderCallbacks&lt;Cursor&gt; 
  {
    public static Context mContext;
  
    private LoaderManager.LoaderCallbacks&lt;Cursor&gt; mLoaderCallbacks;
  
    public static SQLiteDatabase      db;
    public static SimpleCursorAdapter cAdapter;
    public static ListView            lvCustomList;
  
  
    public static final class MyCursorLoader extends SimpleCursorLoader 
    {
      public MyCursorLoader( Context context )
      {
        super( context );
      }
  
      @Override
      public Cursor loadInBackground()
      {
        Cursor cursor = null;
  
        cursor = db.rawQuery( "SELECT rowid _id, Name, Rating FROM Tune ORDER BY Name", null );
  
        cAdapter.swapCursor( cursor );
  
        return cursor;
      }
    }  
  
    @Override
    public Loader&lt;Cursor&gt; onCreateLoader(int id, Bundle args) 
    {
      return new MyCursorLoader( this );
    }
  
    @Override
    public void onLoadFinished( Loader&lt;Cursor&gt; loader, Cursor cursor ) 
    {
  //    cAdapter.swapCursor( cursor );
    }
  
    @Override
    public void onLoaderReset( Loader&lt;Cursor&gt; loader ) 
    {
      cAdapter.swapCursor( null );
    }
  
    @Override
    public void onCreate( Bundle savedInstanceState )
    {
      super.onCreate( savedInstanceState );
      setContentView( R.layout.tune_artist_album_view );
  
      mContext = this;
  
      String path = "/sdcard/MyDb.sqlite";
  
      db = SQLiteDatabase.openDatabase( path, null, 0 );
  
      lvCustomList = (ListView) findViewById( R.id.lv_custom_list );
  
      String[] columns = new String[] { "Name", "Rating" };
  
      int[] to = new int[] { R.id.lv_tune };  
  
      cAdapter = new SimpleCursorAdapter( mContext, R.layout.like_hate_row, null, columns, to, 0 );
  
      lvCustomList.setAdapter( cAdapter );
  
      mLoaderCallbacks = this;
  
      LoaderManager lm = getSupportLoaderManager();
  
      lm.initLoader( 0, null, mLoaderCallbacks );
    }
  }
  </code></pre>
  
  <p>Here is SimpleCursorLoader:</p>
  
  <pre><code>package com.example.sqlitetest;
  
  import android.content.Context;
  import android.database.Cursor;
  import android.support.v4.content.AsyncTaskLoader;
  
  /**
   * Used to write apps that run on platforms prior to Android 3.0. When running
   * on Android 3.0 or above, this implementation is still used; it does not try
   * to switch to the framework's implementation. See the framework SDK
   * documentation for a class overview.
   * 
   * This was based on the CursorLoader class
   */
  public abstract class SimpleCursorLoader extends AsyncTaskLoader&lt;Cursor&gt;
  {
    private Cursor mCursor;
  
    public SimpleCursorLoader( Context context )
    {
      super( context );
    }
  
    /* Runs on a worker thread */
    @Override
    public abstract Cursor loadInBackground();
  
    /* Runs on the UI thread */
    @Override
    public void deliverResult( Cursor cursor )
    {
      if( isReset() )
      {
        // An async query came in while the loader is stopped
        if( cursor != null )
        {
          cursor.close();
        }
        return;
      }
  
      Cursor oldCursor = mCursor;
      mCursor = cursor;
  
      if( isStarted() )
      {
        super.deliverResult( cursor );
      }
  
      if( oldCursor != null &amp;&amp; oldCursor != cursor &amp;&amp; !oldCursor.isClosed() )
      {
        oldCursor.close();
      }
    }
  
    /**
     * Starts an asynchronous load of the contacts list data. When the result is
     * ready the callbacks will be called on the UI thread. If a previous load has
     * been completed and is still valid the result may be passed to the callbacks
     * immediately.
     * &lt;p/&gt;
     * Must be called from the UI thread
     */
    @Override
    protected void onStartLoading()
    {
      if( mCursor != null )
      {
        deliverResult( mCursor );
      }
      if( takeContentChanged() || mCursor == null )
      {
        forceLoad();
      }
    }
  
    /**
     * Must be called from the UI thread
     */
    @Override
    protected void onStopLoading()
    {
      // Attempt to cancel the current load task if possible.
      cancelLoad();
    }
  
    @Override
    public void onCanceled( Cursor cursor )
    {
      if( cursor != null &amp;&amp; !cursor.isClosed() )
      {
        cursor.close();
      }
    }
  
    @Override
    protected void onReset()
    {
      super.onReset();
  
      // Ensure the loader is stopped
      onStopLoading();
  
      if( mCursor != null &amp;&amp; !mCursor.isClosed() )
      {
        mCursor.close();
      }
      mCursor = null;
    }
  }
  </code></pre>