swapCursor()慢:"应用程序可能会做太多的工作在其主线程"。 [英] swapCursor() slow: "The application may be doing too much work on its main thread."

本文介绍了swapCursor()慢:"应用程序可能会做太多的工作在其主线程"。的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直看到应用程序可能会做它的主线程的工作太多了。

这是正在下面我code引起swapCursor()?看起来是这样:如果我将其删除,上面的警告消失

我还是不明白为什么它号称是导致该问题的主线。我提出swapCursor()绕成各种场所,如onLoadFinished()和loadInBackground(),但我得到了相同的结果。

我怎么能叫swapCursor()使这一警告将不会出现?我用SimpleCursorLoader的全部原因是避免阻碍了主线程,但它仍然发生。

 包com.example.sqlitetest;进口的java.util.ArrayList;
进口的java.util.HashMap;
进口的java.util.List;进口android.app.Activity;
进口android.content.Context;
进口android.database.Cursor;
进口android.database.sqlite.SQLiteDatabase;
进口android.os.Bundle;
进口android.support.v4.app.FragmentActivity;
进口android.support.v4.app.LoaderManager;
进口android.support.v4.app.LoaderManager.LoaderCallbacks;
进口android.support.v4.content.Loader;
进口android.support.v4.content.CursorLoader;
进口android.support.v4.widget.SimpleCursorAdapter;
进口android.support.v4.widget.SimpleCursorAdapter.ViewBinder;
进口android.view.Gravity;
进口android.view.MotionEvent;
进口android.view.View;
进口android.view.View.OnTouchListener;
进口android.view.ViewGroup;
进口android.widget.AbsListView;
进口android.widget.AdapterView;
进口android.widget.ImageView;
进口android.widget.LinearLayout;
进口android.widget.LinearLayout.LayoutParams;
进口android.widget.ListView;
进口android.widget.TextView;公共类MainActivity扩展FragmentActivity实现LoaderManager.LoaderCallbacks<&光标GT;
{
  公共静态语境mContext;  私人LoaderManager.LoaderCallbacks<&光标GT; mLoaderCallbacks;  公共静态SQLiteDatabase分贝;
  公共静态SimpleCursorAdapter cAdapter;
  公共静态的ListView lvCustomList;
  公共静态最后一类MyCursorLoader扩展SimpleCursorLoader
  {
    公共MyCursorLoader(上下文的背景下)
    {
      超级(上下文);
    }    @覆盖
    公共光标loadInBackground()
    {
      光标光标= NULL;      光标= db.rawQuery(SELECT ROWID _id,名称,评级从调ORDER BY名,NULL);      cAdapter.swapCursor(光标);      返回游标;
    }
  }  @覆盖
  公共装载机<&光标GT; onCreateLoader(INT ID,捆绑参数)
  {
    返回新MyCursorLoader(本);
  }  @覆盖
  公共无效onLoadFinished(装载机<&光标GT;装载机,光标光标)
  {
// cAdapter.swapCursor(光标);
  }  @覆盖
  公共无效onLoaderReset(装载机<&光标GT;装载机)
  {
    cAdapter.swapCursor(NULL);
  }  @覆盖
  公共无效的onCreate(捆绑savedInstanceState)
  {
    super.onCreate(savedInstanceState);
    的setContentView(R.layout.tune_artist_album_view);    mContext =这一点;    字符串路径=/sdcard/MyDb.sqlite;    DB = SQLiteDatabase.openDatabase(路径,空,0);    lvCustomList =(ListView控件)findViewById(R.id.lv_custom_list);    的String [] =列新的String [] {姓名,等级};    INT []为= INT新[] {} R.id.lv_tune;    cAdapter =新SimpleCursorAdapter(mContext,R.layout.like_hate_row,空,列,至,0);    lvCustomList.setAdapter(cAdapter);    mLoaderCallbacks =这一点;    LoaderManager LM = getSupportLoaderManager();    lm.initLoader(0,空,mLoaderCallbacks);
  }
}

下面是SimpleCursorLoader:

 包com.example.sqlitetest;进口android.content.Context;
进口android.database.Cursor;
进口android.support.v4.content.AsyncTaskLoader;/ **
 *用于编写到Android 3.0的前平台上运行的应用程序。当运行
 *在Android 3.0或以上,这个实现仍然使用;它不会尝试
 *切换到框架的实现。见框架SDK
 *一类的概述文件。
 *
 *这是基于CursorLoader类
 * /
公共抽象类SimpleCursorLoader扩展AsyncTaskLoader<&光标GT;
{
  私人光标mCursor;  公共SimpleCursorLoader(上下文的背景下)
  {
    超级(上下文);
  }  / *运行在一个工作线程* /
  @覆盖
  公共抽象光标loadInBackground();  / *运行在UI线程* /
  @覆盖
  公共无效deliverResult(光标光标)
  {
    如果(isReset())
    {
      //异步查询进来,而装载器停止
      如果(指针!= NULL)
      {
        cursor.close();
      }
      返回;
    }    光标oldCursor = mCursor;
    mCursor =光标;    如果(isStarted())
    {
      super.deliverResult(光标);
    }    如果(oldCursor = NULL&放大器;!&安培; oldCursor =光标和放大器;!&安培;!oldCursor.isClosed())
    {
      oldCursor.close();
    }
  }  / **
   *启动联系人列表数据的异步加载。当结果是
   *准备回调将在UI线程调用。如果previous载有
   *已经完成,仍然是有效的结果可以被传递给该回调
   *立即生效。
   * LT; P />
   *必须从UI线程调用
   * /
  @覆盖
  保护无效onStartLoading()
  {
    如果(mCursor!= NULL)
    {
      deliverResult(mCursor);
    }
    如果(takeContentChanged()|| mCursor == NULL)
    {
      的forceload();
    }
  }  / **
   *必须从UI线程调用
   * /
  @覆盖
  保护无效onStopLoading()
  {
    //尝试如果可能取消当前的负载任务。
    cancelLoad();
  }  @覆盖
  公共无效onCanceled(光标光标)
  {
    如果(光标= NULL&放大器;!&安培;!cursor.isClosed())
    {
      cursor.close();
    }
  }  @覆盖
  保护无效onReset()
  {
    super.onReset();    //确保装载机停止
    onStopLoading();    如果(mCursor = NULL&放大器;!&安培;!mCursor.isClosed())
    {
      mCursor.close();
    }
    mCursor = NULL;
  }
}


解决方案

方法查询() rawQuery()不要做你认为他们做的。值得注意的是,它们实际上并不查询数据库。他们只是配置 SQLiteCursor 他们回来。当您尝试使用光标,它执行查询。

因此​​,在你的 loadInBackground()方法,在两者之间 rawQuery() swapCursor(),电话 getCount将()光标您从<$回来C $ C> rawQuery()。这足以迫使光标来真正做的工作的查询,因此,这项工作是在后台线程中完成的。

I keep seeing "The application may be doing too much work on its main thread."

Is this being caused by swapCursor() in my code below? It appears so: if I remove it, the above warning disappears.

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.

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.

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 );
  }
}

Here is 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;
  }
}

解决方案

Methods like query() and rawQuery() don't do what you think they do. Notably, they do not actually query the database. They merely configure the SQLiteCursor that they return. When you attempt to use that Cursor, it executes the query.

Hence, in your loadInBackground() method, in between rawQuery() and swapCursor(), call getCount() on the Cursor you got back from rawQuery(). That is enough to force the Cursor to really do the work for the query, and therefore that work is done on the background thread.

这篇关于swapCursor()慢:&QUOT;应用程序可能会做太多的工作在其主线程&QUOT;。的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆