問題タブ [android-loader]
For questions regarding programming in ECMAScript (JavaScript/JS) and its various dialects/implementations (excluding ActionScript). Note JavaScript is NOT the same as Java! Please include all relevant tags on your question; e.g., [node.js], [jquery], [json], [reactjs], [angular], [ember.js], [vue.js], [typescript], [svelte], etc.
android - getLoaderResultSynchronously を使用した AsyncTaskLoader の単体テスト
API 呼び出しを行う REST クライアントの単体テストを作成しようとしています。クライアントはライブ アプリケーションでは正常に動作しますが、テスト ケースでは実行できません。
どうやら、ここで LoaderTestCase.getLoaderResultSynchronously() を使用できます (少なくとも Android リファレンスによると、しかし、それは私のローダーを受け入れません。コード:
これにより、エラーgetLoaderResultSynchronously(Loader) in the type LoaderTestCase is not applied for the arguments (RESTLoader) が生成されます。
RESTLoader は AsyncLoader を拡張します。私はサポートライブラリを使用していることに注意してください.おそらくそこにあるローダーは互換性がありませんか? ドキュメントには、これに関する情報はありません。
私はいくつかの方法でこれを解決しようとしましたが、どれもうまくいかないようです:
- リスナーをローダーに登録しました。ただし、コールバックはトリガーされません
- CountdownLatch の使用 (リスナーも使用)。繰り返しますが、トリガー/カウントダウンのタイムアウトはありません。
- 型テンプレート () をいじってみましたが、成功しませんでした。
- SO でも同様のソリューションですが、リスナーに到達できません。
getLoaderResultSynchronously がローダーを受け入れない理由を知っている人はいますか? または、戻りデータをテストする方法を含む、ローダーをテストする別のクリーンな方法はありますか? 別のケースで戻りデータの処理をテストできますが、実際のデータもテストしたいと思います。
心から、
android - LoaderManagerを使用した複数のローダー、適切なローダーが取得されない
2つのローダーがあります。1つはバインドされた戻りデータを2TextViews
に入力し、もう1つはを入力しListView
ます。状況ごとに正しいローダーがロードされることを確認するにはどうすればよいですか?最初のローダー(WR_VIEW
ケース)が作成またはロードされていないように見える場所でエラーが発生してonLoadFinished()
いるため、その列を呼び出さない2番目のローダーにアクセスしているため、「そのような列が見つかりませんエラー」が返されます。
ここで私のonCreate
方法では、リストビュー用のアダプタを設定しました。
私の2つの異なるを作成しますCursorLoader
:
TextViews
私のここと:swapCursor
のためにデータをバインドしますListView
ローダーのリセット:
android - AsyncTaskLoader の 3 番目のタスクが消える
リスト項目をタップすると、詳細セクションが新しく選択された行に関連するデータをロードするリスト/詳細ワークフローを実装しようとしています。AsyncTaskLoader
これを達成するためにを使用しようとしています。3 つのリスト項目を続けて十分にすばやくタップすると、実際には 2 つのロードだけが行われ、3 つ目が失われるという問題が発生しています。
この動作を示すサンプル アクティビティを作成しました。ボタンを 3 回タップすると、loadInBackground()
メソッドは 2 回しか呼び出されません。どこかで電話に出られないのですか?
android - ダイアログ付きのAsyncTaskLoader、それは実行可能ですか?
私は新しいアプリを開始し、Androidの最新のパターンとガイドラインを使用したいと思いました。そのうちの1つは、AsyncTasksの代わりにローダー(AsyncTaskLoader)を使用することです。ローダーが、すべてのAsyncTasks「タスク」を実際に置き換えることになっているのかどうかを確認しようとしています。 "すなわち
REST呼び出しに基づいてアプリを構築したいとします。これらの呼び出しの1つが、ユーザーのログインを担当します。したがって、(フラグメントボタンで)[送信]をクリックすると、応答が返されるまでダイアログが表示されます。正しければ、AsyncTaskLoader onLoadFinishedを使用すると、ハンドラーを使用しない限りダイアログを閉じることができず、これをうまく使用すると、ソリューションは少しハッキーに見えます。その場合、ユーザー名またはパスワードが間違っている場合などのエラーダイアログを表示する必要があります。そうすると、ハンドラーへの呼び出しが大量に発生する可能性があります。
AsyncTaskを使用してこれを簡単に実行し、すべて正常に機能しました。すべてのコードをAsyncTaskLoaderに移動していたので、簡単なはずのときに多くのことをハッキングしているようです。私は初心者なので、しばらくお待ちください。答えます。
お時間をいただきありがとうございます。
android - onLoadFinishedメソッドでアクティビティを開始します
私は持っDialogFragment
ていLoader
ます。
ダイアログは、ユーザーにアプリケーションからログアウトするように促します。
ユーザーがログアウトすることを選択するLoader
と、設定とデータベースをクリアする起動し、現在のを終了しますActivity
。
終了後、ログイン画面でLoader
新しく始めたいのですがActivity
、2つの問題が発生します。
getActivity()
メソッドはnull
Activity
私は外れているので、私は新しく走ることができませんActivity
context
これに対する解決策はありますか?
android - AsyncTaskLoader onLoadFinished 保留中のタスクと構成の変更
AsyncTaskLoader
を使用してバックグラウンドでデータをロードし、選択されたリスト項目に応じて詳細ビューを作成しようとしています。おおむね動作するようになりましたが、まだ 1 つの問題があります。リストで 2 番目の項目を選択し、最初に選択した項目の読み込みが完了する前にデバイスを回転させると、onLoadFinished()
呼び出しは新しいアクティビティではなく停止中のアクティビティに報告されます。これは、単一のアイテムを選択してから回転する場合にうまく機能します。
これが私が使用しているコードです。アクティビティ:
リストフラグメント:
結果フラグメント:
プレーンな s を使用してこれを機能させることができましたが、構成の変更を自動的に処理するため、 sAsyncTask
についてさらに学習しようとしています。Loader
編集: LoaderManagerのソースを見て、問題を追跡した可能性があると思います。構成の変更後にinitLoader
が呼び出されると、期待どおり、LoaderInfo
オブジェクトのmCallbacks
フィールドが の実装として新しいアクティビティで更新されます。LoaderCallbacks
ただし、保留中のローダーがある場合、メインLoaderInfo
オブジェクトにもmPendingLoader
a への参照を持つフィールドがLoaderCallbacks
あり、このオブジェクトはフィールド内の新しいアクティビティで更新されませんmCallbacks
。代わりに、コードは次のようになると思います。
onLoadFinished
保留中のローダーが古いアクティビティ インスタンスを呼び出すのは、このためと思われます。このメソッドにブレークポイントを設定し、デバッガーを使用して欠落していると思われる呼び出しを行うと、すべてが期待どおりに機能します。
新しい質問は次のとおりです。バグを見つけましたか、それともこれは予期された動作ですか?
android - カスタム CursorLoader と ListView をサポートする CursorAdapter の間でデータが同期していない
バックグラウンド:
CursorLoader
を使用する代わりに、SQLite データベースで直接動作するカスタムがありContentProvider
ます。このローダーは、 にListFragment
裏打ちされた で動作しCursorAdapter
ます。ここまでは順調ですね。
簡単にするために、UI に [削除] ボタンがあると仮定します。ユーザーがこれをクリックすると、DB から行を削除onContentChanged()
し、ローダーも呼び出します。また、onLoadFinished()
コールバック時にnotifyDatasetChanged()
、UI を更新するためにアダプターを呼び出します。
問題:
削除コマンドが立て続けに実行される場合、つまり が立て続けにonContentChanged()
呼び出されると、bindView()
古いデータを操作することになります。これは行が削除されたことを意味しますが、ListView はまだその行を表示しようとしています。これにより、カーソル例外が発生します。
私は何を間違っていますか?
コード:
これはカスタムの CursorLoader です ( Diane Hackborn 氏によるこのアドバイスに基づく)
コールバックListFragment
を示すクラスのスニペット。LoaderManager
ユーザーがレコードを追加/削除するたびにrefresh()
呼び出すメソッド。
Myは、オーバーライドされて新しく膨張した行レイアウト XML を返し、を使用して列を行レイアウトの s にバインドするCursorAdapter
通常のものです。newView()
bindView()
Cursor
View
編集1
これを少し掘り下げた後、ここでの根本的な問題は、CursorAdapter
が基になる を処理する方法だと思いますCursor
。私はそれがどのように機能するかを理解しようとしています。
理解を深めるために、次のシナリオを取り上げます。
- がロード
CursorLoader
を終了しCursor
、現在 5 行の を返しているとします。 Adapter
は、これらの行の表示を開始します。を次の位置に移動しCursor
て呼び出すgetView()
- この時点で、リスト ビューがレンダリング中であっても、行 (_id = 2 など) がデータベースから削除されます。
- これが問題です-が削除された行に対応する位置に
CursorAdapter
移動しました。Cursor
メソッドはbindView()
引き続き this を使用してこの行の列にアクセスしようとしますがCursor
、これは無効であり、例外が発生します。
質問:
- この理解は正しいでしょうか?上記のポイント 4 に特に興味があります。ここでは、行が削除されたときに、
Cursor
要求しない限り更新されないという仮定を立てています。 - これが正しいと仮定すると、進行中
CursorAdapter
のイベントのレンダリングを破棄/中止し、代わりに新鮮な( andを介して返される) を使用するように依頼するにはどうすればよいですか?ListView
Cursor
Loader#onContentChanged()
Adapter#notifyDatasetChanged()
PSモデレーターへの質問: この編集は別の質問に移動する必要がありますか?
編集2
さまざまな回答からの提案に基づいて、 s がどのように機能するかについての私の理解に根本的な誤りがあったようLoader
です。次のことがわかります。
Fragment
またはAdapter
を直接操作するべきではありませんLoader
。- はデータのすべての
Loader
変更を監視し、データが変更されるたびAdapter
に新しいものを提供する必要があります。Cursor
onLoadFinished()
この理解を武器に、次の変更を試みました。- 一切の操作はありLoader
ません。現在、refresh メソッドは何もしません。
Loader
また、と の内部で何が起こっているかをデバッグするためContentObserver
に、次のように思いつきました。
Fragment
そして、ここに私のとのスニペットがありますLoaderCallback
これで、DB に変更 (行の追加/削除) があるたびに、のonChange()
メソッドをContentObserver
呼び出す必要があります - 正しいですか? 私はこれが起こっているのを見ません。私ListView
の変化は決して見られません。変更が見られるのは、 を明示的に呼び出しonContentChanged()
た場合だけLoader
です。
ここで何がうまくいかないのですか?
編集3
Loader
わかりましたので、から直接拡張するように書き直しましたAsyncTaskLoader
。DB の変更が更新されていることも、DB に行を挿入/削除するときに呼び出されるonContentChanged()
メソッドも表示されません:-(Loader
いくつかのことを明確にするために:
のコードを使用し
CursorLoader
、Cursor
. ここで、 への呼び出しをContentProvider
自分のDbManager
コードに置き換えました (次に、 を使用DatabaseHelper
してクエリを実行し、 を返しますCursor
)。Cursor cursor = AppGlobals.INSTANCE.getDbManager().getAllCameras();
データベースでの挿入/更新/削除は、
Loader
. ほとんどの場合、DB 操作はバックグラウンドService
で行われ、いくつかのケースではActivity
.DbManager
クラスを直接使用してこれらの操作を実行します。
私がまだ得ていないのは、行が追加/削除/変更されたことを誰が教えてくれるのですか? Loader
言い換えれば、どこでForceLoadContentObserver#onChange()
呼ばれますか?ローダーで、オブザーバーを次の場所に登録しますCursor
。
Cursor
これは、変更されたときに通知する責任があることを意味しmObserver
ます。しかし、私の知る限り、「カーソル」は、DBでデータが変更されたときに、それが指しているデータを更新する「ライブ」オブジェクトではありません。
これが私のローダーの最新の反復です。
android - ローダーが破壊されるのはなぜですか?
ローダーを使用するフラグメントがあります。Fragment は LoaderManager.LoaderCallbacks を実装します。onCreate()
フラグメントので、setRetainInstance(true)
向きの変更などの構成変更でフラグメントが破壊されないようにします。これは期待どおりに機能onDestroy()
し、フラグメントの for は呼び出されません。ただし、デバイスを回転させると、ローダーが破棄されます。デバイスを回転させるたびに、新しいローダーが作成されます。メモリダンプをチェックして、これを確認しました。
- なぜこうなった
- どうすればこれを回避できますか?
編集:混乱を避けるために:ローカル変数ローダーはここでは関係ありません。以前に作成したローダーが存在するかどうかを確認するだけです。以下の更新されたコード (ローカル変数を削除) でも、ローダーは破棄されます。
関連するコードを次に示します。
android - ContentProvider、ローダー、ProgressBar
私はContentProvider
sqlite データベースからデータをフェッチし、 経由でロードするを持っていますLoader
。サーバーからデータをダウンロードしてで更新するService
を実行するによって更新されます。明確であることを願っていますが、念のため:AsyncTask
ContentProvider
ListFragment
ContentProvider
経由Loader
でデータを取得します。ContentProvider
で更新されService
ます。
ここで、アプリを初めて起動したときにローカルの sqlite データベースが空の場合、Service
. 私はむしろProgressBar
この瞬間にショーをしたいと思います(バーではなく、無限の糸車)。しかし、ProgressBar
データベースからの結果がない場合に a を表示すると、外部データベースにレコードがないこの特定のケースでサーバーからデータをフェッチした後でもそこに表示されます (私の場合は非常に頻繁に発生します)。そう:
データが初めてダウンロードされるとき、空でない結果が得られるまで、または仕事が完了するまで
Service
ProgressBar を表示したいと思います。ContentProvider
Service
ContentProvider
何も返されず、ジョブ が終了したService
(そして空の結果がフェッチされた)場合、アプリに「結果が見つかりません」と表示させたいと思います。
私の問題はおそらくListFragment
、Service
がまだ実行中であること、または ts ジョブが終了したことを に通知する方法です。Fragment
つまり、内部の呼び出しへの参照を保存するべきではありませんService
。の考えに反しContentProviders
ますね。では、どうやって?
注: ここでコードのどのフラグメントが役立つかはよくわかりません。そのため、特定のフラグメントを確認する必要があると思われる場合は、コメントで教えてください。ありがとう!
android - Android ローダーをデイジーチェーン接続するのは悪い考えですか?
オンラインで 2 つのソースからデータを取得する必要があり、それぞれの進捗状況を表示したいと考えています。データが収集されたら、リストビューに入力できます。
私の現在の実装は、MyActivity が LoaderCallbacks を実装し、それが MyDataLoader (AsyncTaskLoader を拡張するクラス) のインスタンスを作成することです。MyDataLoader の loadInBackground メソッドでは、すべてのソースからデータをフェッチし、Sqlite db に入力します。このデータベースは全体で使用できます。
問題は、プロセスのどこにいるのかについてユーザーにフィードバックを提供していないことです。
そのため、getLoaderManager().initLoader を使用してローダーをデイジーチェーン接続し、ローダーを作成してから、ローダーマネージャー内のローダーを 1 つずつ反復処理することを考えていました。各ローダーが終了して onLoadFinished に戻ると、progressDialog のテキストを設定して進行状況を示すことができます。
これは悪い考えですか?もっと簡単で良い方法はありますか?