1つの簡単な質問:AsyncTask
に値を返すことは可能ですか?
//AsyncTask is a member class
private class MyTask extends AsyncTask<Void, Void, Void>{
protected Void doInBackground(Void... params) {
//do stuff
return null;
}
@Override
protected void onPostExecute(Void result) {
//do stuff
//how to return a value to the calling method?
}
}
そして、私のActivity
/Fragment
内で:
// The task is started from activity
myTask.execute()
// something like this?
myvalue = myTask.getvalue()
編集:これはずっと前に私がJavaに慣れていない場所で尋ねられました。今はJavaに慣れているので、簡単に要約します:
非同期タスクのポイントは、タスクがasynchronous
であることです。つまり、タスクでexecute()
を呼び出した後、タスクは独自のスレッドで実行を開始します。 asynctaskから値を返すことは、元の呼び出しスレッドが既に他の処理を実行しているため、意味がありません(したがって、タスクは非同期です)。
時間について考える:ある時点で、メインスレッドと並行して実行されるタスクを開始しました。並列実行タスクが完了すると、メインスレッドでも時間が経過しました。並列タスクは、時間をさかのぼってメインスレッドに値を返すことはできません。
私はCから来ていたので、これについてはあまり知りませんでした。しかし、多くの人が同じ質問をしているようですので、私はそれを少し明確にすると思った。
値を処理するメソッドを呼び出さないのはなぜですか?
public class MyClass extends Activity {
private class myTask extends AsyncTask<Void, Void, Void> {
//initiate vars
public myTask() {
super();
//my params here
}
protected Void doInBackground(Void... params) {
//do stuff
return null;
}
@Override
protected void onPostExecute(Void result) {
//do stuff
myMethod(myValue);
}
}
private myHandledValueType myMethod(Value myValue) {
//handle value
return myHandledValueType;
}
}
それが onPostExecute()
の目的です。 UIスレッドで実行され、そこから画面(または必要な他の場所)に結果を配信できます。最終結果が利用可能になるまで呼び出されません。中間結果を配信する場合は、 onProgressUpdate()
をご覧ください
最も簡単な方法は、呼び出し元のオブジェクトを非同期タスクに渡すことです(必要に応じて構築時に):
public class AsyncGetUserImagesTask extends AsyncTask<Void, Void, Void> {
private MyImagesPagerFragment mimagesPagerFragment;
private ArrayList<ImageData> mImages = new ArrayList<ImageData>();
public AsyncGetUserImagesTask(MyImagesPagerFragment imagesPagerFragment) {
this.mimagesPagerFragment = imagesPagerFragment;
}
@Override
public Void doInBackground(Void... records) {
// do work here
return null;
}
@Override
protected void onPostExecute(Void result) {
mimagesPagerFragment.updateAdapter(mImages);
}
}
そして、呼び出し元クラス(アクティビティまたはフラグメント)でタスクを実行します。
public class MyImagesPagerFragment extends Fragment {
@Override
public void onCreate(Bundle savedInstanceState) {
AsyncGetUserImagesTask mGetImagesTask = new AsyncGetUserImagesTask(this);
mGetImagesTask.execute();
}
そして、onPostExecuteMethodは、たとえば以下のように、元のクラスのメソッドを呼び出します。
public void updateAdapter(List<ImageData> images) {
mImageAdapter.setImages(images);
mImageAdapter.notifyDataSetChanged();
}
}
コード例:アクティビティはAsyncTaskを使用してバックグラウンドスレッドで値を取得し、AsyncTaskはprocessValueを呼び出して結果をアクティビティに返します。
public class MyClass extends Activity {
private void getValue() {
new MyTask().execute();
}
void processValue(Value myValue) {
//handle value
//Update GUI, show toast, etc..
}
private class MyTask extends AsyncTask<Void, Void, Value> {
@Override
protected Value doInBackground(Void... params) {
//do stuff and return the value you want
return Value;
}
@Override
protected void onPostExecute(Value result) {
// Call activity method with results
processValue(result);
}
}
}
あなたはこれを試すことができます:myvalue = new myTask().execute().get();
マイナスはasyncronが終了しないまでプロセスをフリーズします;
AsynTask
にデータを委任または提供するには、 "protocols"を使用する必要があります。
デリゲートとデータソース
デリゲートは、そのオブジェクトがプログラムでイベントに遭遇したときに、別のオブジェクトに代わって、または別のオブジェクトと連携して動作するオブジェクトです。 ( Apple定義 )
プロトコルは、いくつかの動作を委任するためのいくつかのメソッドを定義するインターフェースです。
DELEGATE:バックグラウンドスレッドのオブジェクトからのイベントをキャプチャする
AsynkTask:
public final class TaskWithDelegate extends AsyncTask<..., ..., ...> {
//declare a delegate with type of protocol declared in this task
private TaskDelegate delegate;
//here is the task protocol to can delegate on other object
public interface TaskDelegate {
//define you method headers to override
void onTaskEndWithResult(int success);
void onTaskFinishGettingData(Data result);
}
@Override
protected Integer doInBackground(Object... params) {
//do something in background and get result
if (delegate != null) {
//return result to activity
delegate.onTaskFinishGettingData(result);
}
}
@Override
protected void onPostExecute(Integer result) {
if (delegate != null) {
//return success or fail to activity
delegate.onTaskEndWithResult(result);
}
}
}
アクティビティ:
public class DelegateActivity extends Activity implements TaskDelegate {
void callTask () {
TaskWithDelegate task = new TaskWithDelegate;
//set the delegate of the task as this activity
task.setDelegate(this);
}
//handle success or fail to show an alert...
@Override
void onTaskEndWithResult(int success) {
}
//handle data to show them in activity...
@Override
void onTaskFinishGettingData(Data result) {
}
}
EDIT:doInBackgroundでデリゲートを呼び出し、デリゲートがビューを編集しようとすると、ビューはメインスレッドによってのみ操作できるためクラッシュします。
EXTRA
DATASOURCE:バックグラウンドスレッドでオブジェクトにデータを提供する
AsyncTask:
public final class TaskWithDataSource extends AsyncTask<..., ..., ...> {
//declare a datasource with type of protocol declared in this task
private TaskDataSource dataSource;
private Object data;
//here is the task protocol to can provide data from other object
public interface TaskDataSource {
//define you method headers to override
int indexOfObject(Object object);
Object objectAtIndex(int index);
}
@Override
protected void onPreExecute(Integer result) {
if (dataSource != null) {
//ask for some data
this.data = dataSource.objectAtIndex(0);
}
}
@Override
protected Integer doInBackground(Object... params) {
//do something in background and get result
int index;
if (dataSource != null) {
//ask for something more
index = dataSource.indexOfObject(this.data);
}
}
}
アクティビティ:
public class DataSourceActivity extends Activity implements TaskDataSource {
void callTask () {
TaskWithDataSource task = new TaskWithDataSource;
//set the datasource of the task as this activity
task.setDataSource(this);
}
//send some data to the async task when it is needed...
@Override
Object objectAtIndex(int index) {
return new Data(index);
}
//send more information...
@Override
int indexOfObject(Object object) {
return new object.getIndex();
}
}
AsyncTask<Params, Progress, Result>
Params
—タスクの入力データ型Progress
—進捗状況を世界に知らせる方法Result
—タスクの出力データ型のように考える
Result = task(Params)
文字列URLでYourObject
をロードします。
new AsyncTask<String, Void, YourObject>()
{
@Override
protected void onPreExecute()
{
/* Called before task execution; from UI thread, so you can access your widgets */
// Optionally do some stuff like showing progress bar
};
@Override
protected YourObject doInBackground(String... url)
{
/* Called from background thread, so you're NOT allowed to interact with UI */
// Perform heavy task to get YourObject by string
// Stay clear & functional, just convert input to output and return it
YourObject result = callTheServer(url);
return result;
}
@Override
protected void onPostExecute(YourObject result)
{
/* Called once task is done; from UI thread, so you can access your widgets */
// Process result as you like
}
}.execute("http://www.example.com/");
AsyncTaskから結果を取得するには、super.onPostExcecute(result)
;の後に実行する必要があります。これは、バックグラウンドとAsyncTaskも終了したことを意味するためです。例えば。:
... into your async task
@Override
protected void onPostExecute(MyBeanResult result) {
if (dialog.isShowing()) {
dialog.dismiss();
}
if (mWakeLock.isHeld()) {
mWakeLock.release();
}
super.onPostExecute(result);
MyClassName.this.checkResponseForIntent(result);
}
メソドラーcheckResponseForIntentは次のようなものです。
private void checkResponseForIntent(MyBeanResult response) {
if (response == null || response.fault != null) {
noServiceAvailable();
return;
}
... or do what ever you want, even call an other async task...
AsyncTaskの.get()
を使用してこの問題が発生しましたが、ProgressBarはget()
では動作しません。実際、doInBackgroundが終了すると動作します。
それがあなたのお役に立てば幸いです。
MainActivityをAsyncクラスに渡します。したがって、内部クラスのMainActivity関数にアクセスします。これは私には問題ありません。
public class MainActivity extends ActionBarActivity {
void callAsync()
{
Async as = new Async(this,12,"Test");
as.execute();
}
public void ReturnThreadResult(YourObject result)
{
// TO DO:
// print(result.toString());
}
}
public class Async extends AsyncTask<String, String, Boolean> {
MainActivity parent;
int param1;
String param2;
public Async(MainActivity parent,int param1,String param2){
this.parent = parent;
this.param1 = param1;
this.param2 = param2;
}
@Override
protected void onPreExecute(){};
@Override
protected YourObject doInBackground(String... url)
{
return result;
}
@Override
protected void onPostExecute(YourObject result)
{
// call an external function as a result
parent.ReturnThreadResult(result);
}
}