web-dev-qa-db-ja.com

CursorLoaderを使用してListFragmentのSQLiteデータベースにクエリを実行するためのベストプラクティスは?

プロジェクトでAndroid互換性ライブラリを使用しています。DevGuide( http://developer.Android.com/reference/Android/ app/Fragment.html )、および単純なCursorLoaderを使用して、Christianがコンテンツプロバイダーなしで使用できるようにしました( ContentProviderなしのCursorLoaderの使用 )。

質問はです。ListFragment/親アクティビティで、データベースを開いて、カーソルを返し、アダプタとsetListAdapterを作成する必要がありますか?

アプリには、TitlesFragment、DetailsFragment、FragmentLayoutActivity、DetailsLayoutActivityがあります。

ベストプラクティスです...

  • 以下のコードサンプルのように、ListFragmentのonActivityCreatedでデータベースを開き、ListFragmentのonDestroyでデータベースを閉じます。

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        // Open database
        playersDatabaseHelper = new PlayersDBAdapter(getActivity());
        playersDatabaseHelper.open();
        getLoaderManager().initLoader(0, null, this);
        ...
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        if (playersDatabaseHelper != null) {
            playersDatabaseHelper.close();
        }
    }
    
  • データベースにクエリを実行し、カーソルをonCreateLoaderに戻し、以下のコードサンプルのように、アダプタとsetListAdapterをonLoadFinishedに作成します。

    @Override
    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
        // Now create and return a CursorLoader that will take care of
        // creating a Cursor for the data being displayed.
        return new MyCursorLoader(getActivity()) {
            @Override
            public Cursor loadInBackground() {
                playersCursor = playersDatabaseHelper.getAllPlayers();
                return playersCursor;
            }
        };
    
    }
    
    @Override
    public void onLoadFinished(Loader<Cursor> loader, Cursor cursor) {      
        // Create an empty adapter we will use to display the loaded data.
        playersAdapter = new RowAdapter(getActivity(), playersCursor, R.layout.players_overview_row);
    
        // Allocate the adapter to the List displayed within this fragment.
        setListAdapter(playersAdapter);
    
        playersAdapter.swapCursor(cursor);
    
        // The list should now be shown.
        if (isResumed()) {
            setListShown(true);
        } else {
            setListShownNoAnimation(true);
        }
    }
    

私は正しい方向に進んでいますか、それともそれらのいくつかをどこかに移動する必要がありますか?御時間ありがとうございます!

44
micadelli

CursorLoaderとFragmentの経験はありませんが、別のスレッドとアクティビティによる同時アクセスのコンテキストでSQLiteOpenHelperを使用したことはあります。

PlayersDBAdapterが内部的にSQLiteOpenHelperクラスを使用していると想定します。しかし、open()メソッドとclose()メソッドが何をしているのか明確ではありませんか?

私がしたこと:

  • sQLiteOpenHelperをapplicationワイドシングルトンとして定義します。アクティビティワイドではありません。
  • アプリケーションonCreateでSQLiteOpenHelper単一インスタンスをインスタンス化します
  • アクティビティが停止したときに別のインスタンスがDBを開かなければならない可能性があるため、DestroyのアクティビティでSQLiteOpenHelperインスタンスを解放しないでください。
  • SQLiteOpenHelperインスタンスはアプリケーションonTerminateでクリアする必要があると思います(onTerminateが実際にはほとんど呼び出されないため、わかりません)
  • MySQLiteOpenHelper.getWritableDatabase()でSQLiteDatabase参照を取得するDBAdapterオブジェクトがあります
  • これらのDBAdapterは通常、アクティビティonCreateで割り当てられ、onDestroyでリリースされます。

少なくともこれは機能し、数千人のユーザーがいるアプリケーションでクラッシュすることはありません。それを改善するための提案は大歓迎です:-)

6
Thierry