2016-04-26 8 views
2

私はここ数ヶ月間、IOS開発に取り組んでおり、Core DataとNSFetchedResultsControllerを広く使用してきました。Cursor、CursorAdapter、LoaderManager、Loaderの関係

コアデータ+ NSFetchedResultsController:データベースへの変更を自動的に検出し、それに応じてテーブル要素を更新します。

私はAndroid開発に切り替えました。私は上記と同等のものを探していました。私は利用可能なさまざまなクラスを見てきましたが、ちょっと混乱しています。クラスの

異なる種類:

  1. カーソル:データベースクエリの結果へのアクセスを提供します。
  2. CursorAdapter:(list、recycler)ビューをカーソルとリンクし、オブジェクトを表示します。
  3. ContentProvider:データベースオブジェクトへのアクセスを提供します。 LoaderManagerの使用に必要です。
  4. LoaderManager:UIをブロックせずにデータを読み込むためにアクティビティまたはフラグメントによって実装される
  5. ローダー:コンテンツが変更されたときにカーソルオブジェクトを生成するローダー。

私はgreendaoを使用していることに言及する価値があると思います。私は生成されたContentProviderを使用しています。私は少しあやふやだところ

これを更新する流れがある

。これは私の前提です。

  1. コンテンツプロバイダは、LoaderManagerおよび場合によってはCursorAdapterによって使用されるカーソルを保持します。
  2. データベースから変更が発生すると、LoaderにはForceLoadContentObserverがあり、その内容が変更されたときにカーソルを観察してonLoadFinishedを呼び出します。
  3. 通常、カーソルアダプタはonLoadFinished()内にswap()を呼び出し、テーブルを更新します。心の中で上記を維持

、私はのContentProviderを作成し、LoaderManagerを実施したが、私は(greenDaoを使用して)新しいオブジェクトを永続化するとき機能onLoadFinished()が呼び出されていない - 私は理解していますかどうかを問う開始するために私を導きましたプロセスは正しく行われます。これまでに私が一般的にコーディングしたことを示すためのコードスニペットがあります。

断片クラス

public class MissionPageFragment extends Fragment implements LoaderManager.LoaderCallbacks<Cursor> { 

    // Various initialization methods 

    @Override 
    public void onActivityCreated(Bundle savedInstanceState) { 
     super.onActivityCreated(savedInstanceState); 
     getLoaderManager().initLoader(0, savedInstanceState, this); 
    } 

    @Override 
    public Loader onCreateLoader(int id, Bundle args) { 
     ContentProvider.daoSession = Main.daoSession; 
     Uri uri = ContentProvider.CONTENT_URI; 

     // Other initializations 

     CursorLoader cursorLoader = new CursorLoader(getContext(), uri, projections, null, null, null); 
     return cursorLoader; 
    } 

    @Override 
    public void onLoadFinished(Loader<Cursor> loader, Cursor data) { 
     System.out.println("Should be called when a new item is persisted... but not called =("); 
    } 

    // Other methods 
} 

誰かが私が正しくプロセスについて考えていますかどうかの確認および/または間違っているかもしれないものに光を当てることができれば、私はそれをたくさんいただければ幸いです。ここ

編集1

はgreenDaoによって生成のContentProviderサブクラスにおいてquery()関数の抜粋です。

@Override 
public Cursor query(Uri uri, String[] projection, String selection, 
        String[] selectionArgs, String sortOrder) { 

    SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder(); 
    int uriType = sURIMatcher.match(uri); 
    switch (uriType) { 
     case MISSION_DIR: 
      queryBuilder.setTables(TABLENAME); 
      break; 
     case MISSION_ID: 
      queryBuilder.setTables(TABLENAME); 
      queryBuilder.appendWhere(PK + "=" 
        + uri.getLastPathSegment()); 
      break; 
     default: 
      throw new IllegalArgumentException("Unknown URI: " + uri); 
    } 

    SQLiteDatabase db = getDatabase(); 
    Cursor cursor = queryBuilder.query(db, projection, selection, 
      selectionArgs, null, null, sortOrder); 
    cursor.setNotificationUri(getContext().getContentResolver(), uri); 

    return cursor; 
} 

ソリューション

私はちょうど私がGreenDaoと、前述のすべてのクラスを実装する方法を共有したいと思いました。これを行うより良い方法があれば教えてください。しかし、これで十分です。

  1. GreenDaoGeneratorクラスにContentProviderのサブクラスのメソッドが適切に呼び出された場合

    Entity entity = new Entity(); 
    entity.addContentProvider(); 
    
  2. チェックを次のコードスニペットを追加することによって、ContentProviderのサブクラスを生成します。 AndroidManifest.xmlにjavadocの部分を追加します。私にとっては、生成されたContentProviderクラスBASE_PATH変数を次のような別の変数に変更する必要がありました。

    public static final String BASE_PATH = "MYTABLENAME"; 
    
  3. LoaderManager、Loaderを上記のようなActivity/Fragmentクラスに追加します。また、ContentProviderが使用される前にdaoSessionオブジェクトを設定する必要があります。以下のスニペットを別のイニシャライザクラスに移動して、他のアクティビティ/フラグメントクラスでも使用できるようにしました。

    ContentProvider.daoSession = Main.daoSession; 
    
  4. 私はので、私はここにhttps://gist.github.com/skyfishjy/443b7448f59be978bc59少しカスタマイズして提供CursorRecyclerViewAdapterクラスをサブクラス化RecyclerViewを使用しています。 ListViewを使用している場合は、単純なCursorAdapterを使用することができます。 Loaderは更新を待機しているので、Adapterは更新を受信する必要はありません。

  5. 今のContentProviderサブクラスはこれによりライン自動的GreenDaoによって生成さ

    getContext().getContentResolver().notifyChange(uri, null); 
    

    にビューを更新することができます。これは、すべてのCRUD操作にContentProviderを使用でき、ビューが自動的に更新されることを意味します。これは、ORMを使用する目的を無効にしたようです。このように、私は現在通常のGreenDao操作を行い、挿入、削除、更新のたびに手作業でnotifyChangeを呼び出します。

    GreenDaoObj obj = new GreenDaoObj(); 
    obj.insert(); 
    getContext.getContentResolver().notifyChange(MyContentProvider.CONTENT_URI, null); 
    

私は本当にGreenDaoがモデルとダオオブジェクトのためのコードを生成触れたくないとしてこれよりも良い方法があるとは思いません。私は、生成されたCRUDメソッドをネストするカスタムCRUD関数を追加することができますが、それは簡単ではないはずです。

私はこれまで見てきましたが、GreenDaoをLoader/LoaderManagerで使用する方法については十分に文書化されていませんでしたので、ここで整理すると思いました。うまくいけば、これはこれを実装しようとしている人に役立ちます。

+0

LoaderおよびLoaderManagerは、コンテンツを読み込むためのクラスです。これはカーソルにすることもできますが、Jsonやその他のものにすることもできます。また、ローダなしでSQLiteからデータをロードすることもできます。しかし、あなたの例では、ContentProviderはSQLiteからデータをロードし、Cursorを返します。これを行うには、ContentProviderで 'query'をオーバーライドする必要があります(AndroidManifestに追加することを忘れないでください)。 –

+0

私はgreendaoによって生成されたContentProviderサブクラスを使用しています。 (私はContentProviderクラスの専門家はいませんが) – jrhee17

+0

あなたのAndroidManaifestにContentProviderを追加しましたか? - > http://developer.android.com/guide/topics/providers/content-provider -creating.html#ProviderElement –

答えて

3

あなたが正確に正しくしていないものが2,3あります。

  1. ContentProviderは、データへのアクセスを提供するAndroidコンポーネントです。そのデータは、リレーショナルデータベース、フラットファイル、リモートサーバなどに格納することができます。プロバイダには共通のREST風インタフェースがあり、データストレージのさまざまなオプションより抽象レイヤとして機能します。 ContentProviderは外部アプリケーションからもアクセスできます(正しく設定されている場合)。これにより、アプリケーション間でデータを共有するためのデフォルトの方法になります。それらにアクセスするにはLoaderManagerは必要ありません。それらはContentResolverを介してアクセスする必要があります。
  2. LoaderManagerは、Loaderライフサイクルを担当し、ActivityおよびFragmentのライフサイクルと調整します。
  3. Loaderは、アクティビティまたはフラグメントにデータをロードするためのライフサイクル対応の方法を提供します。 CursorLoaderは、機能のトーンを伴う特定の実装です。ワーカースレッドを使用してUIスレッドのロードを維持します。ContentResolverを使用して抽象化し、ContentProviderにアクセスし、ContentObserverを設定します。 ContentObserverは、必要に応じてクエリURLの更新をリッスンし、データをリロードします。

ContentObserver通知が機能するようにするには、いくつかのことが適切に行われていることを確認する必要があります。まず、ContentProviderはオブザーバに変更を伝播する必要があります。これはgetContext().getContentResolver().notifyChange(url, observer)を使用して行われます。通知されたURLのクエリを実行したCursorLoaderがある場合、自動的に再読み込みされます。

+0

フィードバックをお寄せいただきありがとうございます。私はContentObserverを探して、あなたに連絡します。 – jrhee17

+0

あなたのヒントから理解してください。 nその 'loadInBackground'メソッドこれは 'CursorLoader'を意味し、追加の' ContentObserver'を宣言する必要はありません。問題は、ContentProviderの 'insert'メソッドとは対照的にgreendaoの' insert'メソッドを使用していたことです。ありがとうございます – jrhee17

関連する問題