2

アプリの 1 つでパフォーマンスの問題に対処しています。多分あなたの一人が私を助けることができますか?

私は約10kのエントリを持つデータベースを持っています。SQLiteDatabaseクラスのデフォルトのクエリメソッドを使用して要素をクエリします。クエリ自体は十分に高速です。

クエリが完了したら、結果を Google マップに表示する必要があります。そのために、マーカー情報を保持するカーソルから結果配列を生成します。

私が使用する方法は、次のようになります。

    final ArrayList< MarkerElement > result = new ArrayList< MarkerElement >();
    cursor.moveToFirst();
    while ( !cursor.isAfterLast() ) {
        result.add( new MarkerElement(
                cursor.getString( COL_TITLE ),
                cursor.getString( COL_SNIPPET ),
                new LatLng(
                        cursor.getDouble( COL_LAT ),
                        cursor.getDouble( COL_LNG ) ),
                cursor.getString( COL_OTHER_USEFUL_DATA ) );
        cursor.moveToNext();
    }
    cursor.close();

MarkerElementは、Google マップ上のマーカーに必要な値を保持する単純なクラスです

ここでの問題は、すべてのカーソル要素をループするのに非常に時間がかかることです。また、すべての結果を同時に表示する必要があるため、ListView のように結果を遅延ロードするスマートな方法は考えられません。

このプロセスを大幅にスピードアップするためにできることはありますか?

どんな助けでも大歓迎です!

よろしくお願いします

4

1 に答える 1

5

クエリが本当にあなたが思っているほど速いかどうかはわかりません。ほとんどの場合、実際のクエリはcursor.moveToFirst()ステートメントでのみ実行され、query()またはrawQuery()(または使用している他のクエリメソッド)を呼び出すときは実行されません。

とにかく、クエリは、ユーザーを短時間だけ待たせるのに十分な速さである必要があります。そうでない場合は、SELECT * FROM your_table LIMIT START, COUNT (たとえば、最初の 1000 行を取得するには SELECT * FROM your_table LIMIT 0, 1000 ) を使用してチャンクでロードすることを検討してください。

クエリは ui スレッドでは発生しないため、AsyncTaskLoader または CursorLoader で実行する必要があります。https://stackoverflow.com/a/7422343/534471でわかるように、ContentProvider のない CursorLoader が可能です。

それぞれ 1000 レコードに対して 10 個のクエリを実行する必要があると仮定すると、LoaderManager を使用して管理できる CursorLoader が 10 個あることになります。LoaderManager はカーソルを管理 (開いたり閉じたり) し、向きが変わってもカーソルを保持し、すべてをバックグラウンド タスクで実行するため、UI スレッドをブロックしても問題はありません。LoaderManager は、コンテンツが変更された場合にもデータベースを再クエリします ( https://stackoverflow.com/a/5603959/534471を参照)。LoaderManager がフラグメントまたはアクティビティにカーソルの読み込みが完了したことを通知すると、onLoadFinished() が呼び出されます ( http://developer.android.com/reference/android/support/v4/app/LoaderManager.LoaderCallbacks.htmlを参照) 。 .

コードを遅くしているのは、データベースのクエリだけでなく、10,000 の MarkerElement と別の 10,000 の LatLng オブジェクトを作成することです。あなたの要件はわかりませんが、これらのオブジェクトなしで作業する機会があれば、コードを確実に高速化できます。MarkerElements/LatLng を排除するもう 1 つの望ましい効果は、メモリの使用量です。携帯電話を対象とするアプリの場合、3 つの Strings と 2 つの Double を持つ 20,000 個のオブジェクトは相当なものです。

CursorLoaders と LoaderManager を使用すると、カーソルから値を取得し、MarkerElements と LatLng を使用せずに UI ビューを直接設定できます。また、遅延ロードも可能になります。いずれかの CursorLoader に対して onLoadFinished() が呼び出されるたびに、ビューを設定できます (initLoader/restartLoader が非 UI スレッドから呼び出されない限り、onLoadFinished() は UI スレッドで呼び出されます)。1000 個のビューが多すぎて一度に入力できない場合は、クエリを小さな断片に分割するか、10 または 100 のチャンクで (カーソルごとに) ビューを入力するメカニズムを追加します。

ユーザーがマーカーの 1 つを選択するときなど、現在 MarkerElement に格納されている情報が必要な場合は、マーカーを表示するビューで setTag() を使用して、db レコードの主キーを格納します。キーを使用して、データベースからレコードを取得するか、既にクエリされたカーソルからでもレコードを取得します (これにはマッピングメカニズムが必要ですが、実行可能です)。

概要:

  • クエリをいくつかのサブクエリに分割して、より小さいデータ セットを取得します
  • CursorLoaders と CursorManager を使用して、さまざまなクエリ/カーソルを管理します。
  • 行ごとに MarkerElement と LatLng を作成するのではなく、返されたカーソルから直接ビューを設定します。
  • 場合によっては、UI の応答性を維持するために、いくつかの手順で各カーソルの入力を行います。
  • ビューで setTag() を使用して、ビューの背後にあるデータを取得できるようにします
于 2013-04-24T05:03:36.547 に答える