swapCursor() бавен: Приложението може да върши твърде много работа върху основната си нишка.

Продължавам да виждам „Приложението може да върши твърде много работа върху основната си нишка“.

Това причинено ли е от swapCursor() в моя код по-долу? Изглежда така: ако го премахна, горното предупреждение изчезва.

Все още не разбирам защо се твърди, че е основната нишка, която причинява проблема. Преместих swapCursor() на различни места като onLoadFinished() и в loadInBackground(), но получавам същия резултат.

Как мога да извикам swapCursor(), така че това предупреждение да не се появява? Цялата причина, поради която използвах SimpleCursorLoader, беше да избягвам задържането на основната нишка, но все още се случва.

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<Cursor> 
{
  public static Context mContext;

  private LoaderManager.LoaderCallbacks<Cursor> 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<Cursor> onCreateLoader(int id, Bundle args) 
  {
    return new MyCursorLoader( this );
  }

  @Override
  public void onLoadFinished( Loader<Cursor> loader, Cursor cursor ) 
  {
//    cAdapter.swapCursor( cursor );
  }

  @Override
  public void onLoaderReset( Loader<Cursor> 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 );
  }
}

Ето го SimpleCursorLoader:

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<Cursor>
{
  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 && oldCursor != cursor && !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.
   * <p/>
   * 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 && !cursor.isClosed() )
    {
      cursor.close();
    }
  }

  @Override
  protected void onReset()
  {
    super.onReset();

    // Ensure the loader is stopped
    onStopLoading();

    if( mCursor != null && !mCursor.isClosed() )
    {
      mCursor.close();
    }
    mCursor = null;
  }
}

comment
Използвайте Traceview и разберете къде прекарва времето ви, вместо да гадаете.   -  person CommonsWare    schedule 07.07.2014
comment
@CommonsWare: Благодаря, ще го пробвам и ще видя какво показва. Пробвах го на телефона си по обяд и не се появиха предупреждения. Проблемът може да възниква само на моя таблет.   -  person SparkyNZ    schedule 08.07.2014
comment
@CommonsWare: Добре, така че TraceView ми казва, че предположението ми е правилно - 1,5 секунди са изразходвани за извършване на nativeExecuteForCursorWindow() в основната нишка. Защо в основната нишка? Очевидно не съм постигнал целта си извличането на базата данни да се извършва във фонов режим.   -  person SparkyNZ    schedule 08.07.2014


Отговори (1)


Методи като query() и rawQuery() не правят това, което си мислите, че правят. Трябва да се отбележи, че те всъщност не правят заявки в базата данни. Те просто конфигурират SQLiteCursor, който връщат. Когато се опитате да използвате този Cursor, той изпълнява заявката.

Следователно във вашия loadInBackground() метод, между rawQuery() и swapCursor(), извикайте getCount() на Cursor, който сте получили от rawQuery(). Това е достатъчно, за да принуди Cursor наистина да свърши работата за заявката и следователно тази работа се извършва във фоновата нишка.

person CommonsWare    schedule 08.07.2014
comment
Аха! Благодаря за това. Видях извикване getCount() в някои от примерите. Върнатата стойност беше игнорирана и си помислих, че това е само малко останал случаен код - това обяснява присъствието му! Ще го пробвам. Ако това помага, бих могъл да приема отговора ви. - person SparkyNZ; 08.07.2014
comment
@SparkyNZ: Уви, няма метод yoYouLazyObjectDoTheQueryAlready(), в противен случай бихме го използвали за този случай на употреба. :-) - person CommonsWare; 08.07.2014
comment
Да, това свърши работа. Вместо да виждам малък блок от 1,5 секунди в основната нишка, виждам, че ModernAsyncTask върши това количество работа... и няма предупреждения за липсващи кадри. Приех отговора ви - много ви благодаря за това.. и интересно пътуване с TraceView. - person SparkyNZ; 08.07.2014
comment
сега е март 2016 г. и все още се случва за CursorLoader. За щастие го намерих - person nbtk; 21.03.2016