サーチ…


前書き

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);
    ...
}


Modified text is an extract of the original Stack Overflow Documentation
ライセンスを受けた CC BY-SA 3.0
所属していない Stack Overflow