Android
AsyncTask
サーチ…
パラメーター
パラメータ | 詳細 |
---|---|
Params | 実行時にタスクに送信されるパラメータのタイプ。 |
進捗 | バックグラウンド計算中に発行された進行単位のタイプ |
結果 | バックグラウンド計算の結果の型。 |
基本的な使用法
Androidのアクティビティとサービスでは 、ほとんどのコールバックはメインスレッドで実行されます 。これは、UIを更新することが簡単になりますが、メインスレッド上で、プロセッサにまたはI / O-重いタスクを実行すると、あなたのUIが(一時停止し、応答しなくなることがあります公式ドキュメント 、次に何が起こるか上を)。
これらの重いタスクをバックグラウンドスレッドに置くことでこれを解決できます。
これを行うための1つの方法は、バックグラウンドスレッドの使い方を容易にするためのフレームワークを提供するAsyncTaskを使用することです。バックグラウンドスレッドが作業を完了する前、実行中および実行後にUIスレッドタスクを実行します。
AsyncTask
拡張するときにオーバーライドできるメソッド:
-
onPreExecute()
:タスクが実行される前にUIスレッドで呼び出されます。 -
doInBackground()
:onPreExecute()
実行が終了した直後にバックグラウンドスレッドで呼び出されます。 -
onProgressUpdate()
:publishProgress(Progress...)
呼び出し後にUIスレッドで呼び出されpublishProgress(Progress...)
。 -
onPostExecute()
:バックグラウンド計算が終了した後にUIスレッドで呼び出されます。
例
public class MyCustomAsyncTask extends AsyncTask<File, Void, String> {
@Override
protected void onPreExecute(){
// This runs on the UI thread before the background thread executes.
super.onPreExecute();
// Do pre-thread tasks such as initializing variables.
Log.v("myBackgroundTask", "Starting Background Task");
}
@Override
protected String doInBackground(File... params) {
// Disk-intensive work. This runs on a background thread.
// Search through a file for the first line that contains "Hello", and return
// that line.
try (Scanner scanner = new Scanner(params[0])) {
while (scanner.hasNextLine()) {
final String line = scanner.nextLine();
publishProgress(); // tell the UI thread we made progress
if (line.contains("Hello")) {
return line;
}
}
return null;
}
}
@Override
protected void onProgressUpdate(Void...p) {
// Runs on the UI thread after publishProgress is invoked
Log.v("Read another line!")
}
@Override
protected void onPostExecute(String s) {
// This runs on the UI thread after complete execution of the doInBackground() method
// This function receives result(String s) returned from the doInBackground() method.
// Update UI with the found string.
TextView view = (TextView) findViewById(R.id.found_string);
if (s != null) {
view.setText(s);
} else {
view.setText("Match not found.");
}
}
}
使用法:
MyCustomAsyncTask asyncTask = new MyCustomAsyncTask<File, Void, String>();
// Run the task with a user supplied filename.
asyncTask.execute(userSuppliedFilename);
または単に:
new MyCustomAsyncTask().execute(userSuppliedFilename);
注意
AsyncTask
を定義するAsyncTask
は、 < >
間に3つの型を渡すことができます。
<Params, Progress, Result>
( パラメータセクションを参照 )として定義されています。
前の例では<File, Void, String>
型を使用しています:
AsyncTask<File, Void, String>
// Params has type File
// Progress has unused type
// Result has type String
Void
は、型を未使用としてマークする場合に使用されます。
プリミティブ型( int
、 float
など)をパラメータとして渡すことはできません。そのような場合は、 ラッパークラスを渡す必要があります 。たとえば、 int
代わりにInteger
、 Float
代わりにfloat
です。
AsyncTaskおよびActivityのライフサイクル
AsyncTasksはアクティビティインスタンスのライフサイクルに従いません。アクティビティ内でAsyncTaskを開始し、デバイスを回転させると、アクティビティが破棄され、新しいインスタンスが作成されます。しかし、AsyncTaskは死ぬことはありません。それは完了するまで生き続けるでしょう。
ソリューション:AsyncTaskLoader
一つのサブクラスローダーは AsyncTaskLoaderです。このクラスは、AsyncTaskと同じ機能を実行しますが、はるかに優れています。アクティビティの設定変更をより簡単に処理でき、フラグメントやアクティビティのライフサイクル内で動作します。いいことは、AsyncTaskLoaderは、AsyncTaskが使用されているどのような状況でも使用できることです。 Activity / Fragmentが処理するためにいつでもデータをメモリにロードする必要がある場合、AsyncTaskLoaderはより良い仕事をすることができます。
AsyncTaskのキャンセル
YourAsyncTask task = new YourAsyncTask();
task.execute();
task.cancel();
これは進行中の場合、あなたのタスクを止めません。キャンセルされたフラグを設定します。これは、 isCancelled()
戻り値をチェックすることによってチェックできます(コードが現在実行中であると仮定します)。
class YourAsyncTask extends AsyncTask<Void, Void, Void> {
@Override
protected Void doInBackground(Void... params) {
while(!isCancelled()) {
... doing long task stuff
//Do something, you need, upload part of file, for example
if (isCancelled()) {
return null; // Task was detected as canceled
}
if (yourTaskCompleted) {
return null;
}
}
}
}
注意
一方、AsyncTaskがキャンセルされた場合doInBackground(Params... params)
まだ、その後実行されている方法onPostExecute(Result result)
後に呼び出されません doInBackground(Params... params)
戻ります。 AsyncTaskは代わりにonCancelled(Result result)
を呼び出して、実行中にタスクがキャンセルされたことを示します。
発行の進捗状況
時には、 AsyncTask
によって行われる計算の進捗を更新する必要があります。この進展は、文字列、整数などで表すことができます。これを行うには、2つの関数を使用する必要があります。まず、設定する必要がonProgressUpdate
そのパラメータの種類当社の第二種のパラメータと同じである機能AsyncTask
。
class YourAsyncTask extends AsyncTask<URL, Integer, Long> {
@Override
protected void onProgressUpdate(Integer... args) {
setProgressPercent(args[0])
}
}
第二に、我々は関数を使用する必要がpublishProgress
上必ずしもdoInBackground
機能、およびそれがすべてで、従来の方法では、すべての仕事を行います。
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
}
return totalSize;
}
AndroidでAsyncTaskを使用して画像をダウンロードする
このチュートリアルでは、AndroidでAsyncTaskを使用してイメージをダウンロードする方法について説明します。下の例では、ダウンロード中にプログレスバーを表示しながらイメージをダウンロードしています。
Android AsyncTaskについて
非同期タスクを使用すると、Handsをスレッドに追加しなくてもMultiThreadingを実装できます。 AsyncTaskを使用すると、UIスレッドを適切かつ簡単に使用できます。バックグラウンド操作を実行し、UIスレッドで結果を渡すことができます。 UIに関連する何かを分離している、例えばリストに表示するデータをダウンロードする場合は、AsyncTaskを使用してください。- AsyncTasksは、短時間の操作(理想的には数秒以内)に使用するのが理想的です。
- 非同期タスクは、Params、ProgressおよびResult、および
onPreExecute()
、doInBackground()
、onProgressUpdate()
およびonPostExecute()
と呼ばれる3つのジェネリックタイプによって定義されます。 -
onPreExecute()
では、バックグラウンド処理を開始する前に実行する必要があるコードを定義することができます。 - doInBackgroundにはバックグラウンドで実行する必要のあるコードがあります。ここでは
doInBackground()
publishProgress()メソッドで複数回結果をイベントスレッドに送信し、バックグラウンド処理が完了したことを通知して結果を返すことができます。 -
onProgressUpdate()
メソッドは、doInBackground()
メソッドを介して公開されているpublishProgress()
メソッドから進行状況の更新を受け取り、このメソッドはこの進行状況更新を使用してイベントスレッド -
onPostExecute()
メソッドは、doInBackground()
メソッドによって返された結果を処理します。 - 使用されるジェネリックタイプは、
- Params、実行時にタスクに送信されるパラメータのタイプ
- 進捗状況:バックグラウンド計算中に発行された進捗単位のタイプ。
- 結果、バックグラウンド計算の結果のタイプ。
- 非同期タスクがタイプを使用していない場合は、Voidタイプとしてマークすることができます。
- 実行中の非同期タスクは、
cancel(boolean)
メソッドを呼び出すcancel(boolean)
によってcancel(boolean)
ことができます。
Android AsyncTaskを使用して画像をダウンロードする
.xmlレイアウト
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<Button
android:id="@+id/downloadButton"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Click Here to Download" />
<ImageView
android:id="@+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:contentDescription="Your image will appear here" />
</LinearLayout>
.javaクラス
package com.javatechig.droid;
import java.io.InputStream;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import android.app.Activity;
import android.app.ProgressDialog;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.ImageView;
public class ImageDownladerActivity extends Activity {
private ImageView downloadedImg;
private ProgressDialog simpleWaitDialog;
private String downloadUrl = "http://www.9ori.com/store/media/images/8ab579a656.jpg";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.asynch);
Button imageDownloaderBtn = (Button) findViewById(R.id.downloadButton);
downloadedImg = (ImageView) findViewById(R.id.imageView);
imageDownloaderBtn.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
new ImageDownloader().execute(downloadUrl);
}
});
}
private class ImageDownloader extends AsyncTask {
@Override
protected Bitmap doInBackground(String... param) {
// TODO Auto-generated method stub
return downloadBitmap(param[0]);
}
@Override
protected void onPreExecute() {
Log.i("Async-Example", "onPreExecute Called");
simpleWaitDialog = ProgressDialog.show(ImageDownladerActivity.this,
"Wait", "Downloading Image");
}
@Override
protected void onPostExecute(Bitmap result) {
Log.i("Async-Example", "onPostExecute Called");
downloadedImg.setImageBitmap(result);
simpleWaitDialog.dismiss();
}
private Bitmap downloadBitmap(String url) {
// initilize the default HTTP client object
final DefaultHttpClient client = new DefaultHttpClient();
//forming a HttpGet request
final HttpGet getRequest = new HttpGet(url);
try {
HttpResponse response = client.execute(getRequest);
//check 200 OK for success
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w("ImageDownloader", "Error " + statusCode +
" while retrieving bitmap from " + url);
return null;
}
final HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream inputStream = null;
try {
// getting contents from the stream
inputStream = entity.getContent();
// decoding stream data back into image Bitmap that android understands
final Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
return bitmap;
} finally {
if (inputStream != null) {
inputStream.close();
}
entity.consumeContent();
}
}
} catch (Exception e) {
// You Could provide a more explicit error message for IOException
getRequest.abort();
Log.e("ImageDownloader", "Something went wrong while" +
" retrieving bitmap from " + url + e.toString());
}
return null;
}
}
}
現在のところ、例のためのコメントフィールドがない(または私はそれを見つけられていないか、または私はそれのための許可を得ていない)ので、ここにいくつかのコメントがあります:
これは、AsyncTaskで何ができるかを示す良い例です。
しかし、この例では現在、
- メモリリークの可能性
- 非同期タスクが完了する直前に画面が回転した場合、アプリケーションがクラッシュする
詳細は、以下を参照してください。
- WeakReferenceとしてアクティビティを渡してメモリリークを回避する
- http://stackoverflow.com/documentation/android/117/asynctask/5377/possible-problems-with-inner-async-tasks
- AsyncTaskでアクティビティを漏らさないようにする
WeakReferenceとしてアクティビティを渡してメモリリークを回避する
AsyncTaskは、それを呼び出すアクティビティへの参照を要求するのが一般的です。
AsyncTaskがActivityの内部クラスである場合、AsyncTaskとそのメンバー変数/メソッドを直接参照できます。
ただし、AsyncTaskがActivityの内部クラスでない場合は、Activity参照をAsyncTaskに渡す必要があります。これを行うと、発生する可能性のある問題の1つは、AsyncTaskがそのバックグラウンドスレッドで作業を完了するまで、AsyncTaskがアクティビティの参照を保持することです。 AsyncTaskのバックグラウンドスレッドの作業が完了する前にアクティビティが終了または終了すると、AsyncTaskはアクティビティへの参照を保持しているため、ガベージコレクションできません。
その結果、メモリリークが発生します。
これを防ぐには、アクティビティへの直接参照ではなくAsyncTaskでWeakReferenceを使用します。
WeakReferenceを利用するAsyncTaskの例を次に示します。
private class MyAsyncTask extends AsyncTask<String, Void, Void> {
private WeakReference<Activity> mActivity;
public MyAsyncTask(Activity activity) {
mActivity = new WeakReference<Activity>(activity);
}
@Override
protected void onPreExecute() {
final Activity activity = mActivity.get();
if (activity != null) {
....
}
}
@Override
protected Void doInBackground(String... params) {
//Do something
String param1 = params[0];
String param2 = params[1];
return null;
}
@Override
protected void onPostExecute(Void result) {
final Activity activity = mActivity.get();
if (activity != null) {
activity.updateUI();
}
}
}
アクティビティからAsyncTaskを呼び出す:
new MyAsyncTask(this).execute("param1", "param2");
フラグメントからAsyncTaskを呼び出す:
new MyAsyncTask(getActivity()).execute("param1", "param2");
実行命令
最初に導入されたとき、 AsyncTasks
は1つのバックグラウンドスレッドで連続して実行されました。 DONUT
から始めて、これはスレッドのプールに変更され、複数のタスクを並列に動作させることができました。 HONEYCOMB
開始すると、タスクは1つのスレッド上で実行され、並列実行によって発生する一般的なアプリケーションエラーを回避します。
あなたが本当に並列実行したい場合は、呼び出すことができますexecuteOnExecutor(java.util.concurrent.Executor, Object[])
とTHREAD_POOL_EXECUTOR
。
SERIAL_EXECUTOR - >一度に1つのタスクを連続して実行するExecutor。
THREAD_POOL_EXECUTOR - >タスクを並行して実行するために使用できるExecutor。
サンプル :
Task task = new Task();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB)
task.executeOnExecutor(AsyncTask.SERIAL_EXECUTOR, data);
else
task.execute(data);
AsyncTask:タスクの連続実行と並列実行
AsyncTaskは抽象クラスであり、 Thread
クラスを継承しません。 抽象メソッドdoInBackground(Params... params)
があり、タスクを実行するためにオーバーライドされています。このメソッドはAsyncTask.call()
から呼び出されます。
Executorはjava.util.concurrent
パッケージの一部です。
さらに、AsyncTaskには2つのExecutor
が含まれています
THREAD_POOL_EXECUTOR
ワーカースレッドを使用してタスクを並行して実行します。
public static final Executor THREAD_POOL_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE, KEEP_ALIVE, TimeUnit.SECONDS, sPoolWorkQueue, sThreadFactory);
SERIAL_EXECUTOR
それは、タスクを連続的に、すなわち1つずつ実行する。
private static class SerialExecutor implements Executor { }
どちらのExecutor
sが静的であり、それゆえ一つだけTHREAD_POOL_EXECUTOR
と1 SerialExecutor
オブジェクトが存在しますが、あなたはいくつか作成することができAsyncTask
オブジェクトを。
したがって、デフォルトのExecutor( SerialExecutor
)で複数のバックグラウンドタスクを実行しようとすると、これらのタスクはキューに入れられ、順次実行されます。
THREAD_POOL_EXECUTOR
で複数のバックグラウンドタスクを実行しようとすると、それらは並列に実行されます。
例:
public class MainActivity extends Activity {
private Button bt;
private int CountTask = 0;
private static final String TAG = "AsyncTaskExample";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bt = (Button) findViewById(R.id.button);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
BackgroundTask backgroundTask = new BackgroundTask ();
Integer data[] = { ++CountTask, null, null };
// Task Executed in thread pool ( 1 )
backgroundTask.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, data);
// Task executed Serially ( 2 )
// Uncomment the below code and comment the above code of Thread
// pool Executor and check
// backgroundTask.execute(data);
Log.d(TAG, "Task = " + (int) CountTask + " Task Queued");
}
});
}
private class BackgroundTask extends AsyncTask<Integer, Integer, Integer> {
int taskNumber;
@Override
protected Integer doInBackground(Integer... integers) {
taskNumber = integers[0];
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.d(TAG, "Task = " + taskNumber + " Task Running in Background");
publishProgress(taskNumber);
return null;
}
@Override
protected void onPreExecute() {
super.onPreExecute();
}
@Override
protected void onPostExecute(Integer aLong) {
super.onPostExecute(aLong);
}
@Override
protected void onProgressUpdate(Integer... values) {
super.onProgressUpdate(values);
Log.d(TAG, "Task = " + (int) values[0]
+ " Task Execution Completed");
}
}
}
Performボタンを数回クリックすると、タスクが開始され、結果が表示されます。
スレッドプール(1)で実行されたタスク
各タスクは完了するのに1000msかかる。
t = 36sでは、タスク2,3,4は並行して実行されているためキューに入れられ、実行も開始されます。
08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Queued
08-02 19:48:35.815: D/AsyncTaskExample(11693): Task = 1 Task Running in Background
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Queued
08-02 19:48:**36.025**: D/AsyncTaskExample(11693): Task = 2 Task Running in Background
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Queued
08-02 19:48:**36.165**: D/AsyncTaskExample(11693): Task = 3 Task Running in Background
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Queued
08-02 19:48:**36.325**: D/AsyncTaskExample(11693): Task = 4 Task Running in Background
08-02 19:48:**36.815**: D/AsyncTaskExample(11693): Task = 1 Task Execution Completed
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Queued
08-02 19:48:**36.915**: D/AsyncTaskExample(11693): Task = 5 Task Running in Background
08-02 19:48:37.025: D/AsyncTaskExample(11693): Task = 2 Task Execution Completed
08-02 19:48:37.165: D/AsyncTaskExample(11693): Task = 3 Task Execution Completed
----------
コメントTask Executed in thread pool
(1)でTask executed Serially
(2)でTask executed Serially
コメントを外します。
Performボタンを数回クリックすると、タスクが開始され、結果が表示されます。
逐次的にタスクを実行しているため、現在のタスクの実行が完了した後にすべてのタスクが開始されます。したがって、タスク1の実行が完了すると、タスク2のみがバックグラウンドで実行を開始します。逆に。
08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Queued
08-02 19:42:57.505: D/AsyncTaskExample(10299): Task = 1 Task Running in Background
08-02 19:42:57.675: D/AsyncTaskExample(10299): Task = 2 Task Queued
08-02 19:42:57.835: D/AsyncTaskExample(10299): Task = 3 Task Queued
08-02 19:42:58.005: D/AsyncTaskExample(10299): Task = 4 Task Queued
08-02 19:42:58.155: D/AsyncTaskExample(10299): Task = 5 Task Queued
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 1 Task Execution Completed
08-02 19:42:58.505: D/AsyncTaskExample(10299): Task = 2 Task Running in Background
08-02 19:42:58.755: D/AsyncTaskExample(10299): Task = 6 Task Queued
08-02 19:42:59.295: D/AsyncTaskExample(10299): Task = 7 Task Queued
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 2 Task Execution Completed
08-02 19:42:59.505: D/AsyncTaskExample(10299): Task = 3 Task Running in Background
08-02 19:43:00.035: D/AsyncTaskExample(10299): Task = 8 Task Queued
08-02 19:43:00.505: D/AsyncTaskExample(10299): Task = 3 Task Execution Completed
08-02 19:43:**00.505**: D/AsyncTaskExample(10299): Task = 4 Task Running in Background
08-02 19:43:**01.505**: D/AsyncTaskExample(10299): Task = 4 Task Execution Completed
08-02 19:43:**01.515**: D/AsyncTaskExample(10299): Task = 5 Task Running in Background
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 5 Task Execution Completed
08-02 19:43:**02.515**: D/AsyncTaskExample(10299): Task = 6 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 7 Task Running in Background
08-02 19:43:**03.515**: D/AsyncTaskExample(10299): Task = 6 Task Execution Completed
08-02 19:43:04.515: D/AsyncTaskExample(10299): Task = 8 Task Running in Background
08-02 19:43:**04.515**: D/AsyncTaskExample(10299): Task = 7 Task Execution Completed