Androidローダーとフラグメントを使用して奇妙な状況に気づきました。向きの変更後にLoaderManager.initLoader()を呼び出すと、onLoadFinishedが呼び出されません(ただし、ドキュメントはこれを準備する必要があると示唆していますが)この後、同じ状況を説明するGoogleグループに投稿するためのリンクがあります https://groups.google.com/forum/?fromgroups#!topic/Android-developers/aA2vHYxSsk 。サンプルを書きましたFragment.onActivityCreated()で単純なLoaderのみを初期化して、これが発生するかどうかを確認するアプリケーション。
InitLoader()メソッドをFragmentのonResume()コールバック内に配置できます。ローダーのonLoadFinished()はもう2回呼び出されません。
@Override
public void onResume()
{
super.onResume();
getLoaderManager().initLoader(0, null, this);
}
この問題は、すでに閉じられているカーソルを返すCursorLoaderで明らかになりました。
Android.database.StaleDataException: Attempted to access a cursor after it has been closed.
これはバグか見落としだと思います。 initLoader()をonResumeに移動すると動作する可能性がありますが、できたのはローダーを削除することでした。
ローダーを起動するには(onCreateで):
getLoaderManager().initLoader(MUSIC_LOADER_ID, null, this);
その後、私はそれをやった後(基本的にonLoadFinishedの終わりに)
getLoaderManager().destroyLoader(MUSIC_LOADER_ID);
これは予想通りに動作するようで、余分な呼び出しはありません。
呼び出し時点で呼び出し元が開始状態にあり、要求されたローダーが既に存在し、データを生成している場合、コールバックonLoadFinished(Loader、D)
これでonStartLoading関数のようなものを実装することをお勧めします sample
簡単なテストのために試すことができます:
@Override protected void onStartLoading() {
forceLoad();
}
これにより、loadInBackground関数が起動され、次にFragmentでonLoadFinishedが起動されます。
いずれにせよ、もしあなたが何らかのコードを添付したら、私はあなたにもっと助けを与えようとします。
このように2回呼び出されるonLoadFinishedの問題を解決しました。 Fragment.onActivityCreated()で、このようにローダーを初期化します
if (getLoaderManager().getLoader(LOADER_ID) == null) {
getLoaderManager().initLoader(LOADER_ID, bundle, loaderCallbacks);
} else {
getLoaderManager().restartLoader(LOADER_ID, bundle, loaderCallbacks);
}
loaderCallbacksは通常のローダーコールバックを実装します
private LoaderManager.LoaderCallbacks<T> loaderCallbacks
= new LoaderManager.LoaderCallbacks<T>() {
@Override
public Loader<T> onCreateLoader(int id, Bundle args) {
...
...
}
@Override
public void onLoadFinished(Loader<T> loader, T data) {
...
...
}
@Override
public void onLoaderReset(Loader<T> loader) {
...
...
}
};
問題は、2回呼び出されることです。
1。 Fragment.onStartから
2。 FragmentActivity.onStartから
唯一の違いは、Fragment.onStartでmLoaderManager!= nullかどうかをチェックすることです。つまり、onActivityCreatedのように、onStartの前にgetLoadManagerを呼び出すと、ロードマネージャーを取得/作成して呼び出されます。これを回避するには、onResumeのように後で呼び出す必要があります。
この主題のすべての検索は必然的にここに終わるため、自分の経験を追加したかっただけです。 @jpereraが述べたように、ローダーが既に存在する場合、LoaderManagerがonLoadFinished()を呼び出すことが原因でした。私の場合、FragmentPagerにフラグメントがあり、2つのタブをスクロールしてから、その隣で再度スクロールすると、古いフラグメントが作成を開始します。
OnCreate()内にinitLoader()を配置すると、二重のコールバックも発生するため、onResume()内にinitLoader()を配置しました。ただし、イベントのシーケンスはonCreate()になり、ローダーが存在するためLoaderManagerがコールバックを呼び出し、次にonResume()が呼び出されて、別のinitLoader()およびonLoadFinished()シーケンスをトリガーします。 IE、別の二重コールバック。
"Matt" で簡単な解決策を見つけました。すべてのデータがロードされたら(ローダーが複数ある場合)、すべてのローダーを破棄して、コールバックが余分な時間と呼ばれないようにします。
AppCompatActivityを実装する場合は、getSupportLoaderManager()をallケース(destroyLoader/initLoaderなど)で使用していることを再確認してください。 getLoaderManager()とともにgetSupportLoaderManager()を誤って使用したため、同じ問題が発生しました。
私はこの問題に直面していますが、loaderfinishedメソッドでdestroyloader(YOUR_ID)
を呼び出すために使用されています。その後、ローダーはbackgrdoundタスクを2回呼び出しません。
OnLoadFinished(Loader loader、Object data)でデータオブジェクトを比較することもできます。データオブジェクトが既に持っているものと一致する場合、onLoadFinishedが呼び出されたときに何もできません。例えば:
public void onLoadFinished(Loader loader, Object data) {
if(data != null && mData != data){
//Do something
}
}