由于AsyncTask是一个单独的类,如何使OnPostExecute()的结果进入主要活动?


361

我有这两节课。我的主要活动和扩展的一个AsyncTask,现在在我的主要活动,我需要从得到的结果OnPostExecute()AsyncTask。如何将结果传递或获得主要活动?

这是示例代码。

我的主要活动。

public class MainActivity extends Activity{

    AasyncTask asyncTask = new AasyncTask();

    @Override
    public void onCreate(Bundle aBundle) {
        super.onCreate(aBundle);            

        //Calling the AsyncTask class to start to execute.  
        asyncTask.execute(a.targetServer); 

        //Creating a TextView.
        TextView displayUI = asyncTask.dataDisplay;
        displayUI = new TextView(this);
        this.setContentView(tTextView); 
    }

}

这是AsyncTask类

public class AasyncTask extends AsyncTask<String, Void, String> {

TextView dataDisplay; //store the data  
String soapAction = "http://sample.com"; //SOAPAction header line. 
String targetServer = "https://sampletargeturl.com"; //Target Server.

//SOAP Request.
String soapRequest = "<sample XML request>";    



@Override
protected String doInBackground(String... string) {

String responseStorage = null; //storage of the response

try {


    //Uses URL and HttpURLConnection for server connection. 
    URL targetURL = new URL(targetServer);
    HttpURLConnection httpCon = (HttpURLConnection) targetURL.openConnection();
    httpCon.setDoOutput(true);
    httpCon.setDoInput(true);
    httpCon.setUseCaches(false); 
    httpCon.setChunkedStreamingMode(0);

    //properties of SOAPAction header
    httpCon.addRequestProperty("SOAPAction", soapAction);
    httpCon.addRequestProperty("Content-Type", "text/xml; charset=utf-8"); 
    httpCon.addRequestProperty("Content-Length", "" + soapRequest.length());
    httpCon.setRequestMethod(HttpPost.METHOD_NAME);


    //sending request to the server.
    OutputStream outputStream = httpCon.getOutputStream(); 
    Writer writer = new OutputStreamWriter(outputStream);
    writer.write(soapRequest);
    writer.flush();
    writer.close();


    //getting the response from the server
    InputStream inputStream = httpCon.getInputStream(); 
    BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
    ByteArrayBuffer byteArrayBuffer = new ByteArrayBuffer(50);

    int intResponse = httpCon.getResponseCode();

    while ((intResponse = bufferedReader.read()) != -1) {
        byteArrayBuffer.append(intResponse);
    }

    responseStorage = new String(byteArrayBuffer.toByteArray()); 

    } catch (Exception aException) {
    responseStorage = aException.getMessage(); 
    }
    return responseStorage;
}

protected void onPostExecute(String result) {

    aTextView.setText(result);

}       

}   

您可以按照HelmiB的说明创建接口,也可以创建本地广播接收器。Wiki.workassis.com
android-

为什么不使用观察者模式?
JAAAY

Answers:


750

简单:

  1. 创建interface类,其中class String output是可选的,或者可以是您要返回的任何变量。

    public interface AsyncResponse {
        void processFinish(String output);
    }
  2. 转到您的AsyncTask课程,并将interface声明AsyncResponse为字段:

    public class MyAsyncTask extends AsyncTask<Void, Void, String> {
      public AsyncResponse delegate = null;
    
        @Override
        protected void onPostExecute(String result) {
          delegate.processFinish(result);
        }
     }
  3. 在您的主要活动中,需要进行implements交互AsyncResponse

    public class MainActivity implements AsyncResponse{
      MyAsyncTask asyncTask =new MyAsyncTask();
    
      @Override
      public void onCreate(Bundle savedInstanceState) {
    
         //this to set delegate/listener back to this class
         asyncTask.delegate = this;
    
         //execute the async task 
         asyncTask.execute();
      }
    
      //this override the implemented method from asyncTask
      @Override
      void processFinish(String output){
         //Here you will receive the result fired from async class 
         //of onPostExecute(result) method.
       }
     }

更新

我不知道这是你们中许多人的最爱。因此,这是使用简单便捷的方式interface

仍在使用interface。仅供参考,您可以将其合并为AsyncTask类。

AsyncTask课堂上:

public class MyAsyncTask extends AsyncTask<Void, Void, String> {

  // you may separate this or combined to caller class.
  public interface AsyncResponse {
        void processFinish(String output);
  }

  public AsyncResponse delegate = null;

    public MyAsyncTask(AsyncResponse delegate){
        this.delegate = delegate;
    }

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

在你的Activity课上做

public class MainActivity extends Activity {

   MyAsyncTask asyncTask = new MyAsyncTask(new AsyncResponse(){

     @Override
     void processFinish(String output){
     //Here you will receive the result fired from async class 
     //of onPostExecute(result) method.
     }
  }).execute();

 }

或者,再次在Activity上实现接口

public class MainActivity extends Activity 
    implements AsyncResponse{

    @Override
    public void onCreate(Bundle savedInstanceState) {

        //execute the async task 
        new MyAsyncTask(this).execute();
    }

    //this override the implemented method from AsyncResponse
    @Override
    void processFinish(String output){
        //Here you will receive the result fired from async class 
        //of onPostExecute(result) method.
    }
}

如您在上面看到的2个解决方案,第一个和第三个,它需要创建method processFinish,另一个,该方法在调用者参数内部。第三个比较整洁,因为没有嵌套的匿名类。希望这可以帮助

提示:变化String outputString response以及String result不同的匹配类型,以获得不同的对象。


20
将所有内容全部写下来,然后看到您的答案:)这就像是在思考!+1。同样,通过这种方式,多个事物可以监听AsyncTask的结果!
Roloc 2012年

8
我收到nullpointer异常,因为委托设置为null,请
清除

2
只是给.net开发人员的说明,可以使用AutoResetEvents实现此目的,并且还有一个Java实现autoresetevents的实现,但这要干净得多。顺便说一句,ProcessFinish线程安全吗?
席勒(Syler)2013年

13
对于所有获取空指针的人,将您的接口传递给asyncTask类构造函数,然后将其分配给变量,然后对该变量调用processfinish()。作为参考,请参见接受的解决方案。stackoverflow.com/questions/9963691/…– 2014
晴朗

2
@Sunny,您是对的...另外,我们必须为async.delegate = this初始化异步对象。上班..
Ninja_Coder 2014年

24

有几种选择:

  • AsyncTask班级嵌套在班级中Activity。假设您没有在多个活动中使用同一任务,这是最简单的方法。您所有的代码都保持不变,只需将现有任务类移动到活动类内的嵌套类即可。

    public class MyActivity extends Activity {
        // existing Activity code
        ...
    
        private class MyAsyncTask extends AsyncTask<String, Void, String> {
            // existing AsyncTask code
            ...
        }
    }
  • 为您创建一个自定义构造函数AsyncTask,以引用您的Activity。您可以使用实例化该任务new MyAsyncTask(this).execute(param1, param2)

    public class MyAsyncTask extends AsyncTask<String, Void, String> {
        private Activity activity;
    
        public MyAsyncTask(Activity activity) {
            this.activity = activity;
        }
    
        // existing AsyncTask code
        ...
    }

在第二种选择中:如果类不是类,为什么要经历构造函数和字段的痛苦static呢?只需使用fieldOrMethodfrom MyActivityMyActivity.this.fieldOrMethod阴影中的任何一个即可。
TWiStErRob

@TWiStErRob第二假设MyAsyncTask内部类。
quietmint 2015年

1
哦,很抱歉,private/ protected不允许顶级课程,因此我认为它必须是非static内部课程。
TWiStErRob

2
请注意内部类AsyncTask可能是内存泄漏的来源,如此处所述garena.github.io/blog/2014/09/10/android-memory-leaks
Mark Pazon 2015年

2
保持活动引用也是内存泄漏。回调方法远胜于此
OneCricketeer

19

我觉得下面的方法很容易。

我已经声明了一个回调接口

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[] { "Your request to aynchronous task class is giving here.." });


            }
        });

    }



}

谢谢


17

您可以在Main类中尝试此代码。这对我有用,但是我以其他方式实现了方法

try {
    String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
} 
catch (ExecutionException | InterruptedException ei) {
    ei.printStackTrace();
}

2
您能否解释一下为什么这将有助于OP解决他们的问题?
John Odom 2015年

3
那帮助了我。我尝试了其他方式,例如@HelmiB的答案,但没有得到结果
Nicu P

好的,很抱歉给我答复。她需要调用AsyncTask类,然后将参数放入此调用。AsyncTask由3种通用类型定义:1个参数(服务器域或其他参数)2个进度(可以为空),3个结果。所有这些类型可以是:JSONObject,或字符串,或任何数据类型。当您拥有AsyncTask类时,应定义将数据发送到的位置。例如:asyncTask.execute(“ sampletargeturl.com”)。get() ;
Nicu P 2015年

使用这种方法时,我在Logcat上收到警告:“ I / Choreographer:跳过了50帧!该应用程序可能在其主线程上做过多的工作。” 该如何处理?等待AsyncTask返回时,UI是否冻结?
2015年

@NicuP,您可能忘了打电话execute(),查看我的答案,我在那儿添加了评论。您可能要检查我的最新答案。希望这可以帮助。
HelmiB 2015年

16

这个答案可能太迟了,但是当您Activity依赖时,我想提几件事AsyncTask。这将帮助您防止崩溃和内存管理。正如上面的答案中提到的interface,我们也称它们为回调。他们将充当告密者,但在这些情况下永远不会发送引用Activityinterface始终使用引用。

请参考下面的屏幕截图,以了解如何导致问题。

在此处输入图片说明

如您所见,如果我们从AsyncTask一个强大的参考开始,那么就无法保证我们Activity/ Fragment在获取数据之前会一直存在,因此最好WeakReference在这种情况下使用,这也将有助于内存管理,因为我们永远都不会持有我们的强大参考Activity将使其在失真后有资格进行垃圾回收。

查看下面的代码片段,了解如何使用很棒的WeakReference-

MyTaskInformer.java 充当告密者的界面。

public interface MyTaskInformer {

    void onTaskDone(String output);

}

MySmallAsyncTask.javaAsyncTask可以执行长期运行的任务WeakReference

public class MySmallAsyncTask extends AsyncTask<String, Void, String> {

    // ***** Hold weak reference *****
    private WeakReference<MyTaskInformer> mCallBack;

    public MySmallAsyncTask(MyTaskInformer callback) {
        this.mCallBack = new WeakReference<>(callback);
    }

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

        // Here do whatever your task is like reading/writing file
        // or read data from your server or any other heavy task

        // Let us suppose here you get response, just return it
        final String output = "Any out, mine is just demo output";

        // Return it from here to post execute
        return output;
    }

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

        // Here you can't guarantee that Activity/Fragment is alive who started this AsyncTask

        // Make sure your caller is active

        final MyTaskInformer callBack = mCallBack.get();

        if(callBack != null) {
            callBack.onTaskDone(s);
        }
    }
}

MainActivity.java此类用于在该类和此强制方法上启动我的AsyncTask工具。interfaceoverride

public class MainActivity extends Activity implements MyTaskInformer {

    private TextView mMyTextView;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        mMyTextView = (TextView) findViewById(R.id.tv_text_view);

        // Start your AsyncTask and pass reference of MyTaskInformer in constructor
        new MySmallAsyncTask(this).execute();
    }

    @Override
    public void onTaskDone(String output) {

        // Here you will receive output only if your Activity is alive.
        // no need to add checks like if(!isFinishing())

        mMyTextView.setText(output);
    }
}

2
这很棒!一个不可忽视的重要点。
HasH

6

在您的Oncreate()中:

`

myTask.execute("url");
String result = "";
try {
      result = myTask.get().toString();
} catch (InterruptedException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
}catch (ExecutionException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();

}`


6

您可以在几行中完成此操作,只需在调用AsyncTask时覆盖onPostExecute即可。这是给你的一个例子:

new AasyncTask()
{
    @Override public void onPostExecute(String result)
    {
       // do whatever you want with result 
    }
}.execute(a.targetServer);

希望对您有所帮助,祝您愉快:)


它对我不起作用。它只是不进入onPostExecute方法。
弗朗西斯科·罗梅罗

4

人们为什么要这么难。

这应该足够了。

不要在异步任务上实现onPostExecute,而要在Activity上实现它:

public class MainActivity extends Activity 
{

@Override
public void onCreate(Bundle savedInstanceState) {

    //execute the async task 
    MyAsyncTask task = new MyAsyncTask(){
            protected void onPostExecute(String result) {
                //Do your thing
            }       

    }

    task.execute("Param");

}


}

这对我有用。这是最简单,最容易理解的。我认为它正在利用Java的设计功能。谢谢。PS:是否需要添加@Override
旧的盖泽尔

1
否。@ Override只是一个注释。因此,您告诉Java编译器您打算覆盖该方法,并在未这样做的情况下得到通知。
bugdayci

4

你可以调用get()的方法AsyncTask(或过载get(long, TimeUnit))。该方法将一直阻塞直到AsyncTask完成其工作,此时它将返回Result

在创建/启动异步任务与调用get方法之间进行其他工作是明智的,否则您将无法非常有效地利用异步任务。


1
投票失败的vecause get()将阻塞主线程。如果它会阻止,则没有理由使用AsyncTask
GabrielBB

3

您可以编写自己的侦听器。和HelmiB一样的答案但看起来更自然:

创建监听器界面:

public interface myAsyncTaskCompletedListener {
    void onMyAsynTaskCompleted(int responseCode, String result);
}

然后编写异步任务:

public class myAsyncTask extends AsyncTask<String, Void, String> {

    private myAsyncTaskCompletedListener listener;
    private int responseCode = 0;

    public myAsyncTask() {
    }

    public myAsyncTask(myAsyncTaskCompletedListener listener, int responseCode) {
        this.listener = listener;
        this.responseCode = responseCode;
    }

    @Override
    protected void onPreExecute() {
        super.onPreExecute();
    }


    @Override
    protected String doInBackground(String... params) {
        String result;
        String param = (params.length == 0) ? null : params[0];
        if (param != null) {
            // Do some background jobs, like httprequest...
            return result;
        }
        return null;
    }

    @Override
    protected void onPostExecute(String finalResult) {
        super.onPostExecute(finalResult);
        if (!isCancelled()) {
            if (listener != null) {
                listener.onMyAsynTaskCompleted(responseCode, finalResult);
            }
        }
    }
}

最后在活动中实现侦听器:

public class MainActivity extends AppCompatActivity implements myAsyncTaskCompletedListener {

    @Override
    public void onMyAsynTaskCompleted(int responseCode, String result) {

        switch (responseCode) {
            case TASK_CODE_ONE: 
                // Do something for CODE_ONE
                break;
            case TASK_CODE_TWO:
                // Do something for CODE_TWO
                break;
            default: 
                // Show some error code
        }        
    }

这就是您可以调用asyncTask的方式:

 protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Some other codes...
        new myAsyncTask(this,TASK_CODE_ONE).execute("Data for background job");
        // And some another codes...
}

2

嗨,你可以做这样的事情:

  1. 创建实现AsyncTask的类

    // TASK 
    public class SomeClass extends AsyncTask<Void, Void, String>>
    {
    
        private OnTaskExecutionFinished _task_finished_event;
    
        public interface OnTaskExecutionFinished
        {
            public void OnTaskFihishedEvent(String Reslut);
        }
    
        public void setOnTaskFinishedEvent(OnTaskExecutionFinished _event)
        {
            if(_event != null)
            {
                this._task_finished_event = _event;
            }
        }
    
        @Override
        protected void onPreExecute()
        {
            super.onPreExecute();
    
        }
    
        @Override
        protected String doInBackground(Void... params)
        {
            // do your background task here ...
    
            return "Done!";
        }
    
        @Override
        protected void onPostExecute(String result)
        {
            super.onPostExecute(result);
            if(this._task_finished_event != null)
            {
                this._task_finished_event.OnTaskFihishedEvent(result);
            }
            else
            {
                Log.d("SomeClass", "task_finished even is null");
            }
        }
    }
  2. 添加主要活动

    // MAIN ACTIVITY
    public class MyActivity extends ListActivity
    {
       ...
        SomeClass _some_class = new SomeClass();
        _someclass.setOnTaskFinishedEvent(new _some_class.OnTaskExecutionFinished()
        {
        @Override
        public void OnTaskFihishedEvent(String result)
        {
            Toast.makeText(getApplicationContext(),
                    "Phony thread finished: " + result,
                    Toast.LENGTH_SHORT).show();
        }
    
       });
       _some_class.execute();
       ...
     }

1

在您的Activity类中创建一个静态成员。然后在onPostExecute

例如,如果您的AsyncTask的结果是一个字符串,请在您的Activity中创建一个公共静态字符串

public static String dataFromAsyncTask;

然后,在onPostExecuteAsyncTask的中,只需对主类进行静态调用并设置值即可。

MainActivity.dataFromAsyncTask = "result blah";


1
在这种情况下内存泄漏的可能性是什么?
antoid

0

我通过使用线程和处理程序/消息来使其工作。步骤如下:声明进度对话框

ProgressDialog loadingdialog;

创建一个函数以在操作完成后关闭对话框。

   private Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        loadingdialog.dismiss();

    }
    };

编码您的执行细节:

 public void startUpload(String filepath) {
    loadingdialog = ProgressDialog.show(MainActivity.this, "Uploading", "Uploading Please Wait", true);
    final String _path = filepath;
    new Thread() {
        public void run() {
            try {
                UploadFile(_path, getHostName(), getPortNo());
                handler.sendEmptyMessage(0);

            } catch (Exception e) {
                Log.e("threadmessage", e.getMessage());
            }
        }
    }.start();
}

0

您需要使用“协议”将委托或提供数据到AsynTask

代表和数据源

委托是一个在另一个对象遇到程序中的事件时代表另一个对象或与另一个对象协作的对象。(苹果定义

协议是定义一些方法以委派某些行为的接口。

这是一个完整的例子!


0

尝试这个:

public class SomAsyncTask extends AsyncTask<String, Integer, JSONObject> {

    private CallBack callBack;

    public interface CallBack {
        void async( JSONObject jsonResult );
        void sync( JSONObject jsonResult );
        void progress( Integer... status );
        void cancel();
    }

    public SomAsyncTask(CallBack callBack) {
        this.callBack = callBack;
    }

    @Override
    protected JSONObject doInBackground(String... strings) {

        JSONObject dataJson = null;

        //TODO query, get some dataJson

        if(this.callBack != null)
            this.callBack.async( dataJson );// asynchronize with MAIN LOOP THREAD

        return dataJson;

    }

    @Override
    protected void onProgressUpdate(Integer... values) {
        super.onProgressUpdate(values);

        if(this.callBack != null)
            this.callBack.progress(values);// synchronize with MAIN LOOP THREAD

    }

    @Override
    protected void onPostExecute(JSONObject jsonObject) {
        super.onPostExecute(jsonObject);

        if(this.callBack != null)
            this.callBack.sync(jsonObject);// synchronize with MAIN LOOP THREAD
    }

    @Override
    protected void onCancelled() {
        super.onCancelled();

        if(this.callBack != null)
            this.callBack.cancel();

    }
}

和用法示例:

public void onCreate(@Nullable Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);

         final Context _localContext = getContext();
         SomeAsyncTask.CallBack someCallBack = new SomeAsyncTask.CallBack() {

                @Override
                public void async(JSONObject jsonResult) {//async thread
                    //some async process, e.g. send data to server...
                }

                @Override
                public void sync(JSONObject jsonResult) {//sync thread
                    //get result...

                    //get some resource of Activity variable...
                    Resources resources = _localContext.getResources();
                }

                @Override
                public void progress(Integer... status) {//sync thread
                    //e.g. change status progress bar...
                }

                @Override
                public void cancel() {

                }

            };

            new SomeAsyncTask( someCallBack )
                                .execute("someParams0", "someParams1", "someParams2");

    }

0

可能有点落伍,但我提供了执行代码和结果的回调。显然,为了线程安全,您需要注意在执行回调中访问的内容。

AsyncTask的实现:

public class AsyncDbCall<ExecuteType,ResultType> extends AsyncTask<ExecuteType, Void,  
ResultType>
{
    public interface ExecuteCallback<E, R>
    {
        public R execute(E executeInput);
    }
    public interface PostExecuteCallback<R>
    {
        public void finish(R result);
    }

    private PostExecuteCallback<ResultType> _resultCallback = null;
    private ExecuteCallback<ExecuteType,ResultType> _executeCallback = null;


    AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback, PostExecuteCallback<ResultType> postExecuteCallback)
    {
        _resultCallback = postExecuteCallback;
        _executeCallback = executeCallback;
    }

    AsyncDbCall(ExecuteCallback<ExecuteType,ResultType> executeCallback)
    {
        _executeCallback = executeCallback;
    }

    @Override
    protected ResultType doInBackground(final ExecuteType... params)
    {
        return  _executeCallback.execute(params[0]);
    }

    @Override
    protected void onPostExecute(ResultType result)
    {
        if(_resultCallback != null)
            _resultCallback.finish(result);
    }
}

回调:

 AsyncDbCall.ExecuteCallback<Device, Device> updateDeviceCallback = new 
 AsyncDbCall.ExecuteCallback<Device, Device>()
    {
        @Override
        public Device execute(Device device)
        {
            deviceDao.updateDevice(device);
            return device;
        }
    };

最后执行异步任务:

 new AsyncDbCall<>(addDeviceCallback, resultCallback).execute(device);

0

希望您阅读过这篇文章,否则请阅读。

https://developer.android.com/reference/android/os/AsyncTask

根据结果​​数据的性质,您应该选择可以想到的最佳选择。

使用接口是一个不错的选择

其他一些选择是..

  • 如果AsyncTask类是在要使用结果的类中定义的,请使用静态全局变量或get() ,并从外部类使用它(必要时使用volatile变量)。但应了解AsyncTask的进度,或者至少应确保它已完成任务,并且可以通过全局变量/ get()方法获得结果。您可以使用 轮询,onProgressUpdate(Progress ...),同步或接口(哪一种最适合您)

  • 如果Result可以作为sharedPreference条目兼容,或者可以将其另存为内存中的文件,则可以从后台任务本身将其保存,并且可以使用onPostExecute()方法
    在结果可用时得到通知。记忆。

  • 如果字符串足够小,并且将在活动开始时使用。它可以使用意图putExtra() )内 onPostExecute() ,但请记住,静态上下文是不是安全 处理。

  • 如果可能,您可以从onPostExecute()方法中调用静态方法,其结果是您的参数

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.