BoltsフレームにおけるTaskの使い方
15813 ワード
プロジェクト住所:Bolts-Android
Taskは複雑で非同期な作業をよりよく書くために設計されたもので、JavascriptのPromise思想を運用しています.
レスポンスの速いAndroidアプリケーションを構築するためには、UIスレッド内で任意の時間消費動作を実行してはいけません.つまり、UIスレッドのブロックを避けるためには、バックグラウンドで大量の操作を行う必要があります.このプロセスをより簡単にするために、 が一連の は、タスクに基づくコードを整理して実行することができます.あなたの論理をバラバラなコールバック関数に分散させるのではありません.
各
私たちは
あなたのアプリケーションを書くとき、慎重な選択呼び出し
Taskを作成
最初は、
次の方法を使うと、あなた自身の非同期タスクを簡単に作成し、
Taskはあなたが一連の非同期タスクを実行することを許可します.各タスクは前のタスクが完了したら実行します.例えば、ブログのコメントを全部削除したいです.
コードを複数のコールバックに再構成する難しさは、彼らが異なる変数のスコープを持つことにある.Javaは外部ドメインの変数を使用することができますが、前提は彼がfinalとして宣言しなければなりません.これは非常に不便です.これも私たちが
Taskをキャンセルするには、まず
Taskは複雑で非同期な作業をよりよく書くために設計されたもので、JavascriptのPromise思想を運用しています.
レスポンスの速いAndroidアプリケーションを構築するためには、UIスレッド内で任意の時間消費動作を実行してはいけません.つまり、UIスレッドのブロックを避けるためには、バックグラウンドで大量の操作を行う必要があります.このプロセスをより簡単にするために、
Task
というクラスを追加しました.一つのTask
は、非同期動作を表す.通常、Task
に戻る方法を書きます.このTask
は、タスクの結果を継続的に操作する能力を持っています.このTask
が方法によって返されると、それは既にタスクの実行を開始している.Task
は、動作を実行する場所ではなく、特定のスレッドモデルとバインディングされていない.Task
は、他の非同期方法(Callbacks
、AsyncTask
)と比較して多くの利点がある.Task
は、他のTaskを待つ間、スレッドを占有しないので、より少ないシステムリソースを占有する.Task
を実行するときは、Task
を使用するときのように、ピラミッド型のネストコードを書く必要はありません.CallBack
は、入れ子コードと様々な複雑な名前のTask
を必要としないように、分岐、並列、複合型のエラー処理を実行することができます.CallBack
方法各
continueWith
は、Task
パラメータを有するcontinueWith
方法を有する.Continuation
はインタフェースです.Continuation
の方法を実現できます.then
の方法はタスクが完了したときに呼び出します.ここでタスクの完了状態を確認し、対応する処理をしてもいいです.saveAsync(obj).continueWith(new Continuation() {
public Void then(Task task) throws Exception {
if (task.isCancelled()) {
// the save was cancelled.
} else if (task.isFaulted()) {
// the save failed.
Exception error = task.getError();
} else {
// the object was saved successfully.
ParseObject object = task.getResult();
}
return null;
}
});
Taskysは強いタイプのJava泛型を使っています.最初から文法の正しいコードを書きたいと思っています.次は一例を通して詳しく調べてみます./**
Gets a String asynchronously.
*/
public Task getStringAsync() {
// Let's suppose getIntAsync() returns a Task.
return getIntAsync().continueWith(
// This Continuation is a function which takes an Integer as input,
// and provides a String as output. It must take an Integer because
// that's what was returned from the previous Task.
new Continuation() {
// The Task getIntAsync() returned is passed to "then" for convenience.
public String then(Task task) throws Exception {
Integer number = task.getResult();
return String.format("%d", Locale.US, number);
}
}
);
}
多くの場合、前のタスクが成功した時にわずかな作業をしたいだけかもしれません.エラーとジョブがキャンセルされた場合は後で処理してください.then
方法の代わりにonSuccess
方法を使ってもいいです.saveAsync(obj).onSuccess(new Continuation() {
public Void then(Task task) throws Exception {
// the object was saved successfully.
return null;
}
});
Taskチェーンプログラミング私たちは
continueWith
に対していくつかの膜法を行い、複雑な入れ子論理を作成する代わりにチェーン呼び出しをサポートした.Task
の代わりにcontinueWithTask
を使用してもいいです.新しいTaskを返します.continueWith
によって返されたTaskは、新たなタスクの実行が終了する前に終了するとは考えられない.また、continueWithTask
は、新しいTaskバージョンに戻ることができるonSuccessTask
であり、onSuccess
/onSuccess
を使用してより多くの同期動作を実行したり、continueWith
/onSuccessTask
を使用してより多くの非同期動作を実行したりすることができる.final ParseQuery query = ParseQuery.getQuery("Student");
query.orderByDescending("gpa");
findAsync(query).onSuccessTask(new Continuation, Task>() {
public Task then(Task> task) throws Exception {
List students = task.getResult();
students.get(0).put("valedictorian", true);
return saveAsync(students.get(0));
}
}).onSuccessTask(new Continuation>>() {
public Task> then(Task task) throws Exception {
ParseObject valedictorian = task.getResult();
return findAsync(query);
}
}).onSuccessTask(new Continuation, Task>() {
public Task then(Task> task) throws Exception {
List students = task.getResult();
students.get(1).put("salutatorian", true);
return saveAsync(students.get(1));
}
}).onSuccess(new Continuation() {
public Void then(Task task) throws Exception {
// Everything is done!
return null;
}
});
異常処理あなたのアプリケーションを書くとき、慎重な選択呼び出し
continueWithTask
またはcontinueWith
は、異常な伝達方式の制御を助けることができます.onSuccess
を使用して、発生した異常を伝達したり、または何らかの処理を行うことができる.continueWith
を失敗させる異常な方法で考えられますが、実際には、contionationで異常を投げたら、Task
の結果は失敗を示し、この異常を返します.final ParseQuery query = ParseQuery.getQuery("Student");
query.orderByDescending("gpa");
findAsync(query).onSuccessTask(new Continuation, Task>() {
public Task then(Task> task) throws Exception {
List students = task.getResult();
students.get(0).put("valedictorian", true);
// Force this callback to fail.
throw new RuntimeException("There was an error.");
}
}).onSuccessTask(new Continuation>>() {
public Task> then(Task task) throws Exception {
// Now this continuation will be skipped.
ParseObject valedictorian = task.getResult();
return findAsync(query);
}
}).continueWithTask(new Continuation, Task>() {
public Task then(Task> task) throws Exception {
if (task.isFaulted()) {
// This error handler WILL be called.
// The exception will be "There was an error."
// Let's handle the error by returning a new value.
// The task will be completed with null as its value.
return null;
}
// This will also be skipped.
List students = task.getResult();
students.get(1).put("salutatorian", true);
return saveAsync(students.get(1));
}
}).onSuccess(new Continuation() {
public Void then(Task task) throws Exception {
// Everything is done! This gets called.
// The task's result is null.
return null;
}
});
これは、長い文章を書くのに役立ちます.成功した状況だけを扱うチェーンコールは、呼び出しチェーンの最後にエラー処理を記入すればいいです.Taskを作成
最初は、
Task
またはfindAsync
のような方法を用いて単純にsaveAsync
に戻ることができる.しかし、より高級なスキームについては、カスタムTask
を作成したいかもしれません.この需要を実現するために、Task
を作成しました.このオブジェクトは、新しいTaskCompletionSource
を作成し、その実行結果を制御することができます.Task
を作成した後、Task
、setResult
、seterror
を呼び出して、その後の動作をトリガする必要があります.public Task succeedAsync() {
TaskCompletionSource successful = new TaskCompletionSource<>();
successful.setResult("The good result.");
return successful.getTask();
}
public Task failAsync() {
TaskCompletionSource failed = new TaskCompletionSource<>();
failed.setError(new RuntimeException("An error message."));
return failed.getTask();
}
setCancelled
の作成時に彼のある結果が実行されるべき操作を知っていたら、次のような便利な方法を使ってもいいです.Task successful = Task.forResult("The good result.");
Task failed = Task.forError(new RuntimeException("An error message."));
非同期方法を作成次の方法を使うと、あなた自身の非同期タスクを簡単に作成し、
Task
に戻ります.public Task fetchAsync(ParseObject obj) {
final TaskCompletionSource tcs = new TaskCompletionSource<>();
obj.fetchInBackground(new GetCallback() {
public void done(ParseObject object, ParseException e) {
if (e == null) {
tcs.setResult(object);
} else {
tcs.setError(e);
}
}
});
return tcs.getTask();
}
私たちは同様に、あなたがコードブロックでTaskを作成するのに便利な方法を提供します.Task
コードブロックに実行されると、call
は、バックグラウンドスレッド池内でcallInBackground
を実行する.Task.callInBackground(new Callable() {
public Void call() {
// Do a bunch of stuff.
}
}).continueWith(...);
順番にTaskを実行しますTaskはあなたが一連の非同期タスクを実行することを許可します.各タスクは前のタスクが完了したら実行します.例えば、ブログのコメントを全部削除したいです.
ParseQuery query = ParseQuery.getQuery("Comments");
query.whereEqualTo("post", 123);
findAsync(query).continueWithTask(new Continuation, Task>() {
public Task then(Task> results) throws Exception {
// Create a trivial completed task as a base case.
Task task = Task.forResult(null);
for (final ParseObject result : results) {
// For each item, extend the task with a function to delete the item.
task = task.continueWithTask(new Continuation>() {
public Task then(Task ignored) throws Exception {
// Return a task that will be marked as completed when the delete is finished.
return deleteAsync(result);
}
});
}
return task;
}
}).continueWith(new Continuation() {
public Void then(Task ignored) throws Exception {
// Every comment was deleted.
return null;
}
});
複数のタスクを同時に実行Task
方法を呼び出して、複数のwhenall
を同期して実行することができます.Task
は、入力されたすべてのTask.whenall
が実行された後に完了状態としてマークされる新しいTask
を作成します.同時にタスクを実行することは、順番に実行するよりも速いが、システムリソースと帯域幅をより多く消費することができる.ParseQuery query = ParseQuery.getQuery("Comments");
query.whereEqualTo("post", 123);
findAsync(query).continueWithTask(new Continuation, Task>() {
public Task then(Task> results) throws Exception {
// Collect one task for each delete into an array.
ArrayList> tasks = new ArrayList>();
for (ParseObject result : results) {
// Start this delete immediately and add its task to the list.
tasks.add(deleteAsync(result));
}
// Return a new task that will be marked as completed when all of the deletes are
// finished.
return Task.whenAll(tasks);
}
}).onSuccess(new Continuation() {
public Void then(Task ignored) throws Exception {
// Every comment was deleted.
return null;
}
});
Task ExectorsTask
およびTask
のすべての方法は、Task
の例をパラメータとして入力することができる.これは後続のタスクをどこで実行するかをコントロールできます.デフォルトの状態では、continueWith
は現在のスレッドでonSuccess
を実行し、java.util.concurrent.Executor
は自分のスレッドプールで実行し、他のスレッドで自分のExectorを提供しても良い.例えば、特別なスレッドプールでタスクを実行したい場合.static final Executor NETWORK_EXECUTOR = Executors.newCachedThreadPool();
static final Executor DISK_EXECUTOR = Executors.newCachedThreadPool();
final Request request = ...
Task.call(new Callable() {
@Override
public HttpResponse call() throws Exception {
// Work is specified to be done on NETWORK_EXECUTOR
return client.execute(request);
}
}, NETWORK_EXECUTOR).continueWithTask(new Continuation>() {
@Override
public Task then(Task task) throws Exception {
// Since no executor is specified, it's continued on NETWORK_EXECUTOR
return processResponseAsync(response);
}
}).continueWithTask(new Continuation>() {
@Override
public Task then(Task task) throws Exception {
// We don't want to clog NETWORK_EXECUTOR with disk I/O, so we specify to use DISK_EXECUTOR
return writeToDiskAsync(task.getResult());
}
}, DISK_EXECUTOR);
通常のシーンについては、例えば、メインスレッド実行に配信され、デフォルトの実装を提供する.Task.call()
、Callable
.fetchAsync(object).continueWith(new Continuation() {
public Void then(Task object) throws Exception {
TextView textView = (TextView)findViewById(R.id.name);
textView.setText(object.get("name"));
return null;
}
}, Task.UI_THREAD_EXECUTOR);
変数を取り込むコードを複数のコールバックに再構成する難しさは、彼らが異なる変数のスコープを持つことにある.Javaは外部ドメインの変数を使用することができますが、前提は彼がfinalとして宣言しなければなりません.これは非常に不便です.これも私たちが
Task.callInBackgorund
を追加した理由です.各コールバック間で変数を共有することができます.Task.UI_THREAD_EXECUTOR
、Task.BACKGROUND_EXECUTOR
方法を呼び出して、その値を変えるだけでいいです.// Capture a variable to be modified in the Task callbacks.
final Capture successfulSaveCount = new Capture(0);
saveAsync(obj1).onSuccessTask(new Continuation>() {
public Task then(Task obj1) throws Exception {
successfulSaveCount.set(successfulSaveCount.get() + 1);
return saveAsync(obj2);
}
}).onSuccessTask(new Continuation>() {
public Task then(Task obj2) throws Exception {
successfulSaveCount.set(successfulSaveCount.get() + 1);
return saveAsync(obj3);
}
}).onSuccessTask(new Continuation>() {
public Task then(Task obj3) throws Exception {
successfulSaveCount.set(successfulSaveCount.get() + 1);
return saveAsync(obj4);
}
}).onSuccess(new Continuation() {
public Void then(Task obj4) throws Exception {
successfulSaveCount.set(successfulSaveCount.get() + 1);
return null;
}
}).continueWith(new Continuation() {
public Integer then(Task ignored) throws Exception {
// successfulSaveCount now contains the number of saves that succeeded.
return successfulSaveCount.get();
}
});
TaskをキャンセルTaskをキャンセルするには、まず
Capture
を作成し、キャンセルしたいTaskを作成する方法にtokenを送る必要があります.その後、get
を呼び出したら、tokenに関連するすべてのTaskが終了します.CancellationTokenSource cts = new CancellationTokenSource();
Task stringTask = getIntAsync(cts.getToken());
cts.cancel();
非同期タスクをキャンセルするには、変更方法が必要である.set
を受諾し、CancellationTokenSource
を呼び出して、いつ終了するかを決定する./**
Gets an Integer asynchronously.
*/
public Task getIntAsync(final CancellationToken ct) {
// Create a new Task
final TaskCompletionSource tcs = new TaskCompletionSource<>();
new Thread() {
@Override
public void run() {
// Check if cancelled at start
if (ct.isCancellationRequested()) {
tcs.setCancelled();
return;
}
int result = 0;
while (result < 100) {
// Poll isCancellationRequested in a loop
if (ct.isCancellationRequested()) {
tcs.setCancelled();
return;
}
result++;
}
tcs.setResult(result);
}
}.start();
return tcs.getTask();
}