5

私はリストビューを持つフラグメントを持っています。ContentProviderはアトミックを呼び出しますか? onActivityCreated、古いデータを読み込み、onPauseに保存します。

onPause()で、ContentProviderのリストビューのYスクロール位置を保存しています。

onResumeまたはonActivityCreatedの同じフラグメントは、ローダを使用してコンテンツプロバイダからyスクロール位置を取得し、スクロール位置を復元します。

アクティビティ/フラグメントを終了してそれに戻ると、これは機能します。リストビューは、onPauseのcontentproviderに保存されてから最後に開いた場所に戻ります。したがってコードは100%上手くいく。

回転しているデータは問題ではありません。 onPauseはうまく保存しますが、onCreateActivityの後の読み込みによって、onPauseに保存する前のデータである古いデータが取得されます。それは、リストビューが回転前の位置ではなく、アプリケーションを最初に開いたときにOLD位置に戻ることになります。

onPauseでコンテンツプロバイダへの保存がonPauseで完了していないため、回転後に古いデータが読み込まれるようになることは明らかです。

だから、自分の携帯電話上の回転は、この

01:31:33.026: ThreadViewerFragment.java(235):onPause Saved(position:Yposition): 59:-74 
01:31:33.256: ThreadViewerFragment.java(194):onActivityCreated 
01:31:33.266: ThreadViewerFragment.java(309):onLoadFinished Load(position:Yposition): 62:-149 //initial load is of old values 
01:31:33.266: ThreadViewerFragment.java(309):onLoadFinished Load(position:Yposition): 62:-149 
01:31:33.596: ThreadViewerFragment.java(309):onLoadFinished Load(position:Yposition): 59:-74 //this is loaded due to notification by the save in onPause which is supposed to be finished before recreating the new fragment??? 

のように見えるので、注文は正常に見える(活動/フラグメントフローの面で競合状態のようには見えません)が、明らかに、それは代わりに古い値がロードされています59:-74のちょうど保存された値の

saveInstanceStateなどを使用する方法を知っていますが、なぜコードを2倍にする必要がありますか?contentproviderをアトミックに動作させる方法はありますか?

編集:コンテンツプロバイダが実行中にブロックを呼び出すか、それらの呼び出しがアトミックであるのか、それとも誤解であるのか、われわれがまだ理解していないことがまだ分かっていないため、コンテンツプロバイダーとローダーのonPauseで

は、私は私が理解し

@Override 
public void onPause() { 
    super.onPause(); 

    Utils.logv("onPause Saved position: " + mLastRead + ", " + mYPos); 

    ContentValues contentValues = new ContentValues(); 
    contentValues.put(ProductsContract.Products.Y_POS, mYpos); 

    int updateCount = getActivity().getContentResolver().update(
       Uri.parse(ProductsContract.Products.CONTENT_URI + "/" + mId), 
       contentValues, null, null); 
} 

呼び出しがブロッキング呼び出しでなければなりません更新することで上場製品のY位置をオフに保存していて、フラグメントは前に破壊される前に、それが起こります新しいフラグメントは、私は私のローダー

public void onResume() { 
    super.onResume(); 

    getLoaderManager().initLoader(PRODUCTS_LOADER_ID, null, this); 
} 

を起動し、私のローダーに、私は確実に持っているカーソルを、取得履歴書上で回転

を処理するために作成されます古い回転後のデータが、

@Override 
public void onLoadFinished(Loader<Cursor> cursorLoader, Cursor cursor) { 
    if(cursor.moveToFirst()){ 
     mYpos = cursor.getInt(cursor.getColumnIndex(ProductsContract.Products.Y_POS)); 
     Utils.logv("loader: " + mYpos); 
    } 
} 

、他の状況でそう修正再表示結構ですが、回転の後、ローダは一貫して古いデータをお届けします。

おそらく、コンテンツプロバイダ自体ではなく、古くなっているローダーだと思いますか?カーソルが保存され、それが古くても回転後に復元されるということはありますか?声明の上に想定して

+0

Android 2.3のSDK 8サンプルアプリ「NotePad」では確かです。 onResume()の中でブレークポイントを設定するか( "mText.setTextKeepState(note);"の行頭またはその前)、メモを変更したり、スクリーンロックを有効にしたり、スクリーンをロック解除したりします。活性化された。 onResume()を実行し、「String note = mCursor.getString(COLUMN_INDEX_NOTE);」を実行した後、元のメモのテキストが復元されていることを確認する必要があります。 – Huperniketes

答えて

1
It seems like an obvious race condition that the save to the content provider is not completed in the onPause before it is loaded after the rotate. 

は正しいです:

通常、コンテンツプロバイダは、高速であり、このくらいの時間を取ることが想定されていません。しかしContetnProviderSQLiteでバックアップされている場合、データベースにデータを挿入するのに時間がかかることは理解できます。遅延時間は、データとデバイスハードウェアの量によって異なります。

しかし、このアプローチの問題は、ユーザーが画面を回転させるだけで、実際にはデータが1つずつロードされるのを待つのが好きではない場合です。このパス上のRotation should be fast very fast.

代替である、

  • ごのためのあなたの待ち時間あなたがマニフェストタグを設定したタスク(これは、UIが次回、非常に非常に悪い考えを作成されてブロックされます)
  • を完了するために回転の世話をする。

さらに、このパスでは、ローテーションケースを処理するためにのみメモリ内キャッシュを作成します。つまり、まずデータを探すたびにキャッシュ内で見つけようとするたびに、ContentProviderからロードしようとします。キャッシュのキーに同じコンテンツURIを使用できます。そして、書くために、最初にプロバイダのキャッシュに書いてください。

ContentProviderそれには間違いありません。 ContentProviderが必要な場合は、それを使用する必要があります。しかし、回転を扱うために、あなたは他の選択肢を考えることができます。そして、解決策は、ファイルに物を投げ捨て、それを読み取ることです。 SharedPreferencesまたは今のところ私の頭の上にある典型的なファイルIO。私は彼らが存在するのは正当な理由だと思う。

最後に、ちょうど好奇心から、データonResumeのフラグメントの状態をロードしてみましたか?そして、うまくいけばsetRetainInstance(boolean)があなたのコードのどこかに設定されていません。

編集

私の知る限り、ContentProviderのないプロバイダ任意のアトミックまたはスレッドの安全性を行います。 Androidのドキュメントから、

the methods query(), insert(), delete(), update(), and getType()—are called 
from a pool of threads in the content provider's process, not the UI thread 
for the process. Because these methods might be called from any number of 
threads at the same time, they too must be implemented to be thread-safe. 

私はあなたのコードを見ることができればおそらく私はあなたのより良い答えを与えることができるようになりますthisthis

をお読みください。

+0

私はまだ、コンテンツ提供者が原子であるかどうかは不思議です。私が理解できないことは、contentproviderコールがafaikコールをブロックしていることです。 onresumeとoncreate(私が読み込んだところ)はonpauseの後に呼び出されます(私が読んだところで)。 実際に原子性を破壊していることを理解することは、長い道のりになります。 私は回避策があります。これは、saveoninstancestateを使用して、ローテーションを通して保存する必要があるデータを使用することです。ローダが新しいアクティビティで複数回戻ってくるという点で、ちょっと複雑になっただけです。なぜそれが何回も戻ってくると、私は知らない。 –

+0

申し訳ありませんが、minhazですが、問題の要点が不足しています。ユーザーが戻るボタンを押したためにActivity(またはActivityFragment)インスタンスが破棄されているときに、onPause()の1回の呼び出しで動作する動作は、画面がロックされているためActivity(またはActivityFragment)が破棄されたときに機能しません。システム。 ContentProviderの動作は異なります。私たちは理由を探していて、それが期待どおりになるようにする方法を探しています。 – Huperniketes

+0

ContentProviderは、潜在的な多数のソースからコンテンツプロバイダの単一のインスタンスに送信されたクエリのマーシャリングとアンマーシャリングを行います。 しかし、これは、アクセスが原子であるかどうかを理解する上でさらに重要になります。 私のonPauseコードを追加します。私はUIスレッドで保存を行っています。ブロックする必要があり、その後に新しいアクティビティが作成されたときに新しいデータを保持するはずです。 –

関連する問題