Android
ローダ
サーチ…
前書き
oncreateメソッドが呼び出されたときにバックグラウンドでデータをロードしたい場合は、Loaderはメモリリークを防ぐのに適しています。たとえば、oncreateメソッドでAsynctaskを実行し、別のAsyncTaskを再度実行するアクティビティが再作成されるように画面を回転させると、おそらくAsynTaskが2つ並行して実行されます。
パラメーター
クラス | 説明 |
---|---|
LoaderManager | 1つ以上のLoaderインスタンスを管理するためのActivityまたはFragmentに関連付けられた抽象クラス。 |
LoaderManager.LoaderCallbacks | クライアントがLoaderManagerとやりとりするためのコールバックインターフェイス。 |
ローダ | データの非同期読み込みを実行する抽象クラスです。 |
AsyncTaskLoader | 作業を行うAsyncTaskを提供する抽象ローダー。 |
CursorLoader | ContentResolverを照会してCursorを返すAsyncTaskLoaderのサブクラスです。 |
備考
Android 3.0で導入されたローダーを使用すると、アクティビティやフラグメント内のデータを非同期で読み込むことが容易になります。ローダーには次の特徴があります。
- それらはすべてのアクティビティーとフラグメントで使用できます。
- それらは、データの非同期ロードを提供します。
- 彼らはデータの出所を監視し、コンテンツが変更されたときに新しい結果を提供します。
- 構成変更後に再作成されると、最後のローダーのカーソルに自動的に再接続します。したがって、データを再クエリする必要はありません。
ローダーを使用しない場合
バックグラウンドタスクを完了する必要がある場合は、ローダーを使用しないでください。 Androidは、Loaderが属しているActivities / Fragmentと共に破棄します。完了するまで実行しなければならないタスクを実行したい場合は、ローダーを使用しないでください。代わりに、この種のサービスにサービスを使用する必要があります。基本AsyncTaskLoader
AsyncTaskLoader
は、作業を行うAsyncTask
を提供する抽象Loader
です。
ここではいくつかの基本的な実装:
final class BasicLoader extends AsyncTaskLoader<String> {
public BasicLoader(Context context) {
super(context);
}
@Override
public String loadInBackground() {
// Some work, e.g. load something from internet
return "OK";
}
@Override
public void deliverResult(String data) {
if (isStarted()) {
// Deliver result if loader is currently started
super.deliverResult(data);
}
}
@Override
protected void onStartLoading() {
// Start loading
forceLoad();
}
@Override
protected void onStopLoading() {
cancelLoad();
}
@Override
protected void onReset() {
super.onReset();
// Ensure the loader is stopped
onStopLoading();
}
}
通常、 Loader
はアクティビティのonCreate()
メソッド内、またはフラグメントのonActivityCreated()
内で初期化されます。また、通常、アクティビティまたはフラグメントはLoaderManager.LoaderCallbacks
インターフェイスを実装します。
public class MainActivity extends Activity implements LoaderManager.LoaderCallbacks<String> {
// Unique id for loader
private static final int LDR_BASIC_ID = 1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Initialize loader; Some data can be passed as second param instead of Bundle.Empty
getLoaderManager().initLoader(LDR_BASIC_ID, Bundle.EMPTY, this);
}
@Override
public Loader<String> onCreateLoader(int id, Bundle args) {
return new BasicLoader(this);
}
@Override
public void onLoadFinished(Loader<String> loader, String data) {
Toast.makeText(this, data, Toast.LENGTH_LONG).show();
}
@Override
public void onLoaderReset(Loader<String> loader) {
}
}
この例では、ローダーが完了すると、トーストと結果が表示されます。
キャッシュ付きAsyncTaskLoader
ロードされた結果をキャッシュして、同じデータを複数回ロードすることを避けることは良い方法です。
キャッシュを無効にするにはonContentChanged()
をonContentChanged()
必要があります。 loaderがすでに開始されている場合は、 forceLoad()
が呼び出されます。そうでなければ(ローダーが停止状態の場合)loaderはtakeContentChanged()
checkをtakeContentChanged()
コンテンツの変更を理解できます。
備考: onContentChanged()
は、プロセスのメインスレッドから呼び出す必要があります。
takeContentChanged()に関するJavadocsのコメント:
ローダーのコンテンツが停止中に変更されたかどうかを示す現在のフラグを取得します。それがあった場合はtrueが返され、フラグがクリアされます。
public abstract class BaseLoader<T> extends AsyncTaskLoader<T> {
// Cached result saved here
private final AtomicReference<T> cache = new AtomicReference<>();
public BaseLoader(@NonNull final Context context) {
super(context);
}
@Override
public final void deliverResult(final T data) {
if (!isReset()) {
// Save loaded result
cache.set(data);
if (isStarted()) {
super.deliverResult(data);
}
}
}
@Override
protected final void onStartLoading() {
// Register observers
registerObserver();
final T cached = cache.get();
// Start new loading if content changed in background
// or if we never loaded any data
if (takeContentChanged() || cached == null) {
forceLoad();
} else {
deliverResult(cached);
}
}
@Override
public final void onStopLoading() {
cancelLoad();
}
@Override
protected final void onReset() {
super.onReset();
onStopLoading();
// Clear cache and remove observers
cache.set(null);
unregisterObserver();
}
/* virtual */
protected void registerObserver() {
// Register observers here, call onContentChanged() to invalidate cache
}
/* virtual */
protected void unregisterObserver() {
// Remove observers
}
}
リロード
古いデータを無効にして既存のローダーを再起動するには、 restartLoader()
メソッドを使用します。
private void reload() {
getLoaderManager().reastartLoader(LOADER_ID, Bundle.EMPTY, this);
}
バンドルを使用してパラメータを渡す
Bundleでパラメータを渡すことができます:
Bundle myBundle = new Bundle();
myBundle.putString(MY_KEY, myValue);
onCreateLoaderの値を取得します。
@Override
public Loader<String> onCreateLoader(int id, final Bundle args) {
final String myParam = args.getString(MY_KEY);
...
}