web-dev-qa-db-ja.com

AndroidのAsyncTaskから値を返します

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から来ていたので、これについてはあまり知りませんでした。しかし、多くの人が同じ質問をしているようですので、私はそれを少し明確にすると思った。

111
tom91136

値を処理するメソッドを呼び出さないのはなぜですか?

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;
    }
}
33
ababzy

それが onPostExecute() の目的です。 UIスレッドで実行され、そこから画面(または必要な他の場所)に結果を配信できます。最終結果が利用可能になるまで呼び出されません。中間結果を配信する場合は、 onProgressUpdate() をご覧ください

40
Ted Hopp

最も簡単な方法は、呼び出し元のオブジェクトを非同期タスクに渡すことです(必要に応じて構築時に):

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();
    }
}
23

コード例:アクティビティは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);
    }
  }
}
11
jt-gilkeson

あなたはこれを試すことができます:myvalue = new myTask().execute().get();マイナスはasyncronが終了しないまでプロセスをフリーズします;

11
EugenUngurean

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();
    }
}
8
IgniteCoders

汎用パラメーターを使用する

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/");
3
Nikita Bosik

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が終了すると動作します。

それがあなたのお役に立てば幸いです。

3
Klaus Villaca

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);
    }
  }  
2
Hamid