web-dev-qa-db-ja.com

android asynctaskがコールバックをUIに送信

アクティビティ内にない次のasynctaskクラスがあります。アクティビティでは、asynctaskを初期化しています。asynctaskがコールバックをアクティビティに報告するようにします。出来ますか?または、asynctaskはアクティビティと同じクラスファイルにある必要がありますか?

protected void onProgressUpdate(Integer... values) 
{
    super.onProgressUpdate(values);
    caller.sometextfield.setText("bla");
}

このようなもの?

142
Asaf Nevo

interfaceを作成し、AsyncTaskに(コンストラクターで)渡してから、onPostExecute()のメソッドを呼び出すことができます。

例えば:

あなたのインターフェース:

public interface OnTaskCompleted{
    void onTaskCompleted();
}

あなたの活動:

public class YourActivity implements OnTaskCompleted{
    // your Activity
}

そして、あなたのAsyncTask:

public class YourTask extends AsyncTask<Object,Object,Object>{ //change Object to required type
    private OnTaskCompleted listener;

    public YourTask(OnTaskCompleted listener){
        this.listener=listener;
    }

    // required methods

    protected void onPostExecute(Object o){
        // your stuff
        listener.onTaskCompleted();
    }
}

編集

この回答は非常に人気があったため、いくつか追加します。

Android開発を初めて使用する場合は、AsyncTaskを使用すると、UIスレッドをブロックせずに動作させることができます。実際にいくつかの問題を解決します。クラス自体の動作に問題はありません。ただし、次のような影響があります。

  • メモリリークの可能性。 Activityへの参照を保持すると、ユーザーが画面を離れた(またはデバイスを回転させた)後でもメモリに残ります。
  • AsyncTaskが既に破棄されている場合、ActivityActivityに結果を配信していません。これらすべてを管理するためにコードを追加するか、操作を2回行う必要があります。
  • Activityのすべてを実行する複雑なコード

Androidに移行するのに十分成熟したと感じたら、 この記事 を見てください。非同期でAndroidアプリを開発するためのより良い方法ですオペレーション。

386
Dmitry Zaytsev

以下のアプローチは非常に簡単だと感じました。

コールバック用のインターフェイスを宣言しました

public interface AsyncResponse {
    void processFinish(Object output);
}

次に、すべてのタイプの並列リクエストに応答する非同期タスクを作成しました

 public class MyAsyncTask extends AsyncTask<Object, Object, Object> {

    public AsyncResponse delegate = null;//Call back interface

    public MyAsyncTask(AsyncResponse asyncResponse) {
        delegate = asyncResponse;//Assigning call back interfacethrough constructor
    }

    @Override
    protected Object doInBackground(Object... params) {

    //My Background tasks are written here

      return {resutl Object}

    }

    @Override
    protected void onPostExecute(Object result) {
        delegate.processFinish(result);
    }

}

次に、アクティビティクラスのボタンをクリックしたときに非同期タスクを呼び出しました。

public class MainActivity extends Activity {

    @Override
    public void onCreate(Bundle savedInstanceState) {

        Button mbtnPress = (Button) findViewById(R.id.btnPress);

        mbtnPress.setOnClickListener(new View.OnClickListener() {

            @Override
            public void onClick(View v) {

                MyAsyncTask asyncTask =new MyAsyncTask(new AsyncResponse() {

                    @Override
                    public void processFinish(Object output) {
                        Log.d("Response From Asynchronous task:", (String) output);          
                        mbtnPress.setText((String) output);
                    }
                });
                asyncTask.execute(new Object[] { "Youe request to aynchronous task class is giving here.." });

            }
        });
    }
}

ありがとう

44
Arshad

上記の回答の完了時に、非同期呼び出しごとにフォールバックをカスタマイズすることもできます。これにより、一般的なASYNCメソッドへの各呼び出しは、そこに置くonTaskDoneの内容に応じて異なるデータを取り込みます。

  Main.FragmentCallback FC= new  Main.FragmentCallback(){
            @Override
            public void onTaskDone(String results) {

                localText.setText(results); //example TextView
            }
        };

new API_CALL(this.getApplicationContext(), "GET",FC).execute("&Books=" + Main.Books + "&args=" + profile_id);

思い出してください:私はこのように「メイン」が来るメインアクティビティthatsでインターフェースを使用しました:

public interface FragmentCallback {
    public void onTaskDone(String results);


}

APIのポスト実行は次のようになります。

  @Override
    protected void onPostExecute(String results) {

        Log.i("TASK Result", results);
        mFragmentCallback.onTaskDone(results);

    }

APIコンストラクターは次のようになります。

 class  API_CALL extends AsyncTask<String,Void,String>  {

    private Main.FragmentCallback mFragmentCallback;
    private Context act;
    private String method;


    public API_CALL(Context ctx, String api_method,Main.FragmentCallback fragmentCallback) {
        act=ctx;
        method=api_method;
        mFragmentCallback = fragmentCallback;


    }
6
Miguel

私は他の人が言ったことを繰り返しますが、それをもっと簡単にしようとします...

まず、Interfaceクラスを作成します

public interface PostTaskListener<K> {
    // K is the type of the result object of the async task 
    void onPostTask(K result);
}

次に、具象クラスを含めることにより、インターフェイスを使用するAsyncTask(アクティビティまたはフラグメントの内部静的クラス)を作成します。この例では、PostTaskListenerはStringでパラメーター化されています。つまり、非同期タスクの結果としてStringクラスが必要です。

public static class LoadData extends AsyncTask<Void, Void, String> {

    private PostTaskListener<String> postTaskListener;

    protected LoadData(PostTaskListener<String> postTaskListener){
        this.postTaskListener = postTaskListener;
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);

        if (result != null && postTaskListener != null)
            postTaskListener.onPostTask(result);
    }
}

最後に、ロジックを組み合わせる部分。アクティビティ/フラグメントで、PostTaskListenerを作成し、非同期タスクに渡します。以下に例を示します。

...
PostTaskListener<String> postTaskListener = new PostTaskListener<String>() {
    @Override
    public void onPostTask(String result) {
        //Your post execution task code
    }
}

// Create the async task and pass it the post task listener.
new LoadData(postTaskListener);

できた!

2
ichalos