web-dev-qa-db-ja.com

AsyncTaskLoaderの基本的な例。 (アンドロイド)

私はアプリケーションでローダーを使用しており、このローダーを使用してCOntactsで実行したクエリから得られた結果に基づいて、いくつかの計算を実行し、それらをSqlite DBに保存します。私はこの操作を非同期にしたいのですが、返されるデータ型がたくさんあるため、または単純なハンドラーまたはAsyncTaskLoaderを使用する必要があるため、Asyncタスクを使用することで混乱しています。ローダー。 AsyncTaskLoaderの例を探してみましたが、ロケットサイエンスのように思えます。私のシナリオでの3つのいずれかの基本的で単純な機能の例は、非常に役立ちます。

21
Skynet

AsyncTaskLoaderを使用する場合は、 here's の素敵なサンプルをご覧ください。

編集: this repo )に基づいて、よりシンプルなソリューションを作成することにしました:

public abstract class AsyncTaskLoaderEx<T> extends AsyncTaskLoader<T> {
    private static final AtomicInteger sCurrentUniqueId = new AtomicInteger(0);
    private T mData;
    public boolean hasResult = false;

    public static int getNewUniqueLoaderId() {
        return sCurrentUniqueId.getAndIncrement();
    }

    public AsyncTaskLoaderEx(final Context context) {
        super(context);
        onContentChanged();
    }

    @Override
    protected void onStartLoading() {
        if (takeContentChanged())
            forceLoad();
        //this part should be removed from support library 27.1.0 :
        //else if (hasResult)
        //    deliverResult(mData);
    }

    @Override
    public void deliverResult(final T data) {
        mData = data;
        hasResult = true;
        super.deliverResult(data);
    }

    @Override
    protected void onReset() {
        super.onReset();
        onStopLoading();
        if (hasResult) {
            onReleaseResources(mData);
            mData = null;
            hasResult = false;
        }
    }

    protected void onReleaseResources(T data) {
        //nothing to do.
    }

    public T getResult() {
        return mData;
    }
}

使用法:

あなたの活動で:

        getSupportLoaderManager().initLoader(TASK_ID, TASK_BUNDLE, new LoaderManager.LoaderCallbacks<Bitmap>() {
            @Override
            public Loader<Bitmap> onCreateLoader(final int id, final Bundle args) {
                return new ImageLoadingTask(MainActivity.this);
            }

            @Override
            public void onLoadFinished(final Loader<Bitmap> loader, final Bitmap result) {
                if (result == null)
                    return;
                //TODO use result
            }

            @Override
            public void onLoaderReset(final Loader<Bitmap> loader) {
            }
        });

内部の静的クラス、または通常のクラス:

private static class ImageLoadingTask extends AsyncTaskLoaderEx<Bitmap> {

    public ImageLoadingTask (Context context) {
        super(context);
    }

    @Override
    public Bitmap loadInBackground() {
        //TODO load and return bitmap
    }
}

更新:サポートライブラリ27.1.0以降、少し変更されました(link here ):

バージョン27.1.0では、onStartLoading()はアクティビティが開始されるたびに呼び出されます。 onStartLoading()でdeliverResult()を呼び出すため、onLoadFinished()をトリガーします。これは意図したとおりに機能しています。

必要ないため、onStartLoading()からdeliverResult()への呼び出しを削除する必要があります(ローダーは、追加作業なしでloadInBackground()で計算された結果を既に配信しています)。

この変更のために上記のコードを更新しました。


編集:更新、kotlinバージョンを見つけることができます- ここ

29

Honeycombとv4 Compatibility Libraryから、AsyncTaskLoaderを使用できます。私が理解していることから、AsyncTaskLoaderは画面の反転のような設定変更を通して生き残ることができます。しかし、AsyncTaskを使用すると、構成の変更を台無しにすることができます。

重要な情報:AsyncTaskLoaderLoaderのサブクラスです。このクラスはAsyncTaskと同じ機能を実行しますが、少し改善されており、構成の変更(画面の向き)の処理にも役立ちます。

非常に良い例と説明がここにあります。 http://www.javacodegeeks.com/2013/01/Android-loaders-versus-asynctask.html

GoogleにはAPIドキュメントに直接良い例があります。 Android Design Patternsは、ローダーの背後にある詳細と推論を提供します。

このチュートリアルは間違いなくあなたを助けます。 http://www.javacodegeeks.com/2013/08/Android-custom-loader-to-load-data-directly-from-sqlite-database.html

12
DeepakPanwar

AsyncTaskLoaderを実装するための段階的なチュートリアルを次に示します。またはMediumに関する同じ記事をご覧ください

  1. MainActivityに_LoaderManager.LoaderCallbacks<String>_を実装し、ローダーを一意に識別する_static int_を作成し、文字列URLをローダーに渡すStringキーを作成します

    _public class MainActivity extends AppCompatActivity 
                 implements LoaderManager.LoaderCallbacks<String>{
        public static final int OPERATION_SEARCH_LOADER = 22;
        public static final String OPERATION_QUERY_URL_EXTRA = "query";
    //...}
    _
  2. MainActivity内のonCreateLoaderonLoadFinishedおよびonLoaderReset関数をオーバーライドします

    _@Override
    public Loader<String> onCreateLoader(int id, final Bundle args) {
        //Here we will initiate AsyncTaskLoader
        return null;
    }
    
    @Override
    public void onLoadFinished(Loader<String> loader, String operationResult) {
        //Think of this as AsyncTask onPostExecute method, the result from onCreateLoader will be available in operationResult variable and here you can update UI with the data fetched.
        Log.d("MAINACTIVITY","result : "+ operationResult);
    }
    
    @Override
    public void onLoaderReset(Loader<String> loader) {
        //Don't bother about it, Android Studio will override it for you
    }
    _
  3. inside onCreateLoader()は、コンストラクターのパラメーターとしてthisを持つ匿名内部クラスとして新しい_AsyncTaskLoader<String>_を返し、匿名内部クラス内でloadInBackgroundonStartLoadingをオーバーライドします

    _@Override
    public Loader<String> onCreateLoader(int id, final Bundle args) {
        return new AsyncTaskLoader<String>(this) {
            @Override
            public String loadInBackground() {
                //Think of this as AsyncTask doInBackground() method, here you will actually initiate Network call
                return null;
            }
    
            @Override
            protected void onStartLoading() {
               //Think of this as AsyncTask onPreExecute() method,start your progress bar,and at the end call forceLoad(); 
               forceLoad();
            }
        };
    }
    _
  4. 内部loadInBackgroundは、HTTPUrlConnection、OKHttp、または使用するものを使用してネットワーク呼び出しを行います。

    _ @Override
        public String loadInBackground() {
            String url = args.getString(OPERATION_QUERY_URL_EXTRA);//This is a url in string form 
            if (url!=null&&"".equals(url)) {
                return null;//if url is null, return
            }
            String operationResult="";
            try {
                operationResult = NetworkUtils.getResponseFromHttpUrl(url);//This just create a HTTPUrlConnection and return result in strings
            } catch (IOException e) {
                e.printStackTrace();
            }
            return operationResult;
        }
    _
  5. 内部onCreateは、OPERATION_SEARCH_LOADERをIDとしてローダーを初期化します。バンドルの場合はnull、コンテキストの場合はthis

    _getSupportLoaderManager().initLoader(OPERATION_SEARCH_LOADER, null, this);
    _
  6. ローダーをトリガーしたいときはいつでも、このメソッドを呼び出します

    _private void makeOperationSearchQuery(String url) {
    
        // Create a bundle called queryBundle
        Bundle queryBundle = new Bundle();
        // Use putString with OPERATION_QUERY_URL_EXTRA as the key and the String value of the URL as the value
        queryBundle.putString(OPERATION_QUERY_URL_EXTRA,url);
        // Call getSupportLoaderManager and store it in a LoaderManager variable
        LoaderManager loaderManager = getSupportLoaderManager();
        // Get our Loader by calling getLoader and passing the ID we specified
        Loader<String> loader = loaderManager.getLoader(OPERATION_SEARCH_LOADER);
        // If the Loader was null, initialize it. Else, restart it.
        if(loader==null){
            loaderManager.initLoader(OPERATION_SEARCH_LOADER, queryBundle, this);
        }else{
            loaderManager.restartLoader(OPERATION_SEARCH_LOADER, queryBundle, this);
        }
    }
    _

これで完了です。NetworkUtils.getResponseFromHttpUrl(url);は、カスタム関数で、文字列をURLに変換し、HTTPUrlConnectionの作成に使用します。

10
Sanjeev

この簡単な例 AsyncTaskおよびAsyncTaskLoader が気に入っています。

class FooLoader extends AsyncTaskLoader {
   public FooLoader(Context context, Bundle args) {
      super(context);
      // do some initializations here
   }
   public String loadInBackground() {
      String result = "";
      // ...
      // do long running tasks here
      // ...
      return result;
   }
} 


class FooLoaderClient implements LoaderManager.LoaderCallbacks {
   Activity context;
   // to be used for support library:
   // FragmentActivity context2;
   public Loader onCreateLoader(int id, Bundle args) {
      // init loader depending on id
      return new FooLoader(context, args);
   }
   public void onLoadFinished(Loader loader, String data) {
      // ...
      // update UI here
      //
   }
   public void onLoaderReset(Loader loader) {
      // ...
   }
   public void useLoader() {
      Bundle args = new Bundle();
      // ...
      // fill in args
      // ...
      Loader loader = 
         context.getLoaderManager().initLoader(0, args, this);
      // with support library: 
      // Loader loader = 
      //    context2.getSupportLoaderManager().initLoader(0, args, this);
      // call forceLoad() to start processing
      loader.forceLoad();
   }
}
7
JDOaktown

一生懸命単純化

  private void loadContent() {
    getLoaderManager().initLoader(1000, new Bundle(), 
      new LoaderManager.LoaderCallbacks<List<String>>() {

      @Override
      public Loader<List<String>> onCreateLoader(int id, Bundle args) {
        return new AsyncTaskLoader<List<String>>(MainActivity.this.getApplicationContext()) {

          @Override
          public List<String> loadInBackground() {
            Log.i("B", "Load background data ");
            ArrayList<String> data = new ArrayList<>();
            for (int i = 0; i < 5000; i++) {
              data.add("Data." + i + " " + System.currentTimeMillis());
            }
            try {
              Thread.sleep(5000);
            } catch (InterruptedException e) {
              e.printStackTrace();
            }
            return data;
          }
        };
      }

      @Override
      public void onLoadFinished(Loader<List<String>> loader, List<String> data) {
        Log.i("B", "Here are your data loaded" + data);
        if (!loader.isAbandoned()) {
          mAdapter.setData(data); // Read also about RecyclerView
        }
      }

      @Override
      public void onLoaderReset(Loader<List<String>> loader) {
        Log.i("B", "Loader reset");
      }
    }).forceLoad();
  }

  @Override
  protected void onDestroy() {
    // Abandon the loader so that it should not attempt to modify already dead GUI component
    getLoaderManager().getLoader(1000).abandon();
    super.onDestroy();
  }

これをアクティビティの一部にします。サンプルは遅延をシミュレートしますが、タイムスタンプの接尾辞が異なるため、新しいエントリを簡単に認識できます。もちろん、データを表示するにはRecyclerViewも必要です。 この質問 に対する答えは非常に良いようです。

この例のローダーは、親アクティビティへの参照を保持する内部クラスです。本番環境では、このような参照のない外部静的クラスでなければなりません。

1
h22

Bolts-Androidの使用を好みます。これはとても簡単だ。

https://github.com/BoltsFramework/Bolts-Android

Task.callInBackground(new Callable<Void>() {
  public Void call() {
    // Do a bunch of stuff.
  }
}).continueWith(...);
0
Behrouz.M