Android 由于 AsyncTask 是一个单独的类,如何将 OnPostExecute() 的结果获取到主要活动?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12575068/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 11:04:06  来源:igfitidea点击:

How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?

androidandroid-asynctask

提问by Stella

I have this two classes. My main Activity and the one that extends the AsyncTask, Now in my main Activity I need to get the result from the OnPostExecute()in the AsyncTask. How can I pass or get the result to my main Activity?

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

Here is the sample codes.

这是示例代码。

My main Activity.

我的主要活动。

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

}

This is the AsyncTask class

这是 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);

}       

}   

回答by HelmiB

Easy:

简单:

  1. Create interfaceclass, where String outputis optional, or can be whatever variables you want to return.

    public interface AsyncResponse {
        void processFinish(String output);
    }
    
  2. Go to your AsyncTaskclass, and declare interface AsyncResponseas a field :

    public class MyAsyncTask extends AsyncTask<Void, Void, String> {
      public AsyncResponse delegate = null;
    
        @Override
        protected void onPostExecute(String result) {
          delegate.processFinish(result);
        }
     }
    
  3. In your main Activity you need to implementsinterface 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.
       }
     }
    
  1. 创建interface类, whereString output是可选的,或者可以是你想要返回的任何变量。

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

    public class MyAsyncTask extends AsyncTask<Void, Void, String> {
      public AsyncResponse delegate = null;
    
        @Override
        protected void onPostExecute(String result) {
          delegate.processFinish(result);
        }
     }
    
  3. 在您的主 Activity 中,您需要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.
       }
     }
    


UPDATE

更新

I didn't know this is such a favourite to many of you. So here's the simple and convenience way to use interface.

我不知道这是你们许多人的最爱。所以这里是使用interface.

still using same interface. FYI, you may combine this into AsyncTaskclass.

仍在使用相同的interface. 仅供参考,您可以将其合并到AsyncTask课程中。

in AsyncTaskclass :

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

do this in your Activityclass

在你的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();

 }

Or, implementing the interface on the Activity again

或者,再次在 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.
    }
}

As you can see 2 solutions above, the first and third one, it needs to create method processFinish, the other one, the method is inside the caller parameter. The third is more neat because there is no nested anonymous class. Hope this helps

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

Tip: Change String output, String response, and String resultto different matching types in order to get different objects.

提示:将String outputString response、 和更改String result为不同的匹配类型以获得不同的对象。

回答by quietmint

There are a few options:

有几个选项:

  • Nest the AsyncTaskclass within your Activityclass. Assuming you don't use the same task in multiple activities, this is the easiest way. All your code stays the same, you just move the existing task class to be a nested class inside your activity's class.

    public class MyActivity extends Activity {
        // existing Activity code
        ...
    
        private class MyAsyncTask extends AsyncTask<String, Void, String> {
            // existing AsyncTask code
            ...
        }
    }
    
  • Create a custom constructor for your AsyncTaskthat takes a reference to your Activity. You would instantiate the task with something like 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
        ...
    }
    
  • 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
        ...
    }
    

回答by Arshad

I felt the below approach is very easy.

我觉得下面的方法很简单。

I have declared an interface for callback

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

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

Then created asynchronous Task for responding all type of parallel requests

然后创建异步任务来响应所有类型的并行请求

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

}

Then Called the asynchronous task when clicking a button in activity Class.

然后在活动类中单击按钮时调用异步任务。

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.." });


            }
        });

    }



}

Thanks

谢谢

回答by Nicu P

You can try this code in your Main class. That worked for me, but i have implemented methods in other way

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

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

回答by Rahul

This answer might be late but I would like to mention few things when your Activitydependent on AsyncTask. That would help you in prevent crashes and memory management. As already mentioned in above answers go with interface, we also say them callbacks. They will work as an informer, but never ever send strongreference of Activityor interfacealways use weakreference in those cases.

这个答案可能晚了,但当你Activity依赖AsyncTask. 这将帮助您防止崩溃和内存管理。正如在上面的答案中已经提到的那样interface,我们也说它们是回调。他们将作为告密者工作,但在这些情况下永远不会发送引用Activityinterface始终使用引用。

Please refer to below screenshot to findout how that can cause issues.

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

enter image description here

在此处输入图片说明

As you can see if we started AsyncTaskwith a strongreference then there is no guarantee that our Activity/Fragmentwill be alive till we get data, so it would be better to use WeakReferencein those cases and that will also help in memory management as we will never hold the strong reference of our Activitythen it will be eligible for garbage collection after its distortion.

正如你所看到的,如果我们从AsyncTask一个引用开始,那么在我们获得数据之前不能保证我们的Activity/Fragment会一直存在,所以WeakReference在这些情况下使用会更好,这也将有助于内存管理,因为我们永远不会持有我们的强引用Activity则在其失真后将有资格进行垃圾收集。

Check below code snippet to find out how to use awesome WeakReference -

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

MyTaskInformer.javaInterface which will work as an informer.

MyTaskInformer.java将作为告密者工作的界面。

public interface MyTaskInformer {

    void onTaskDone(String output);

}

MySmallAsyncTask.javaAsyncTask to do long running task, which will use WeakReference.

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.javaThis class is used to start my AsyncTaskimplement interfaceon this class and overridethis mandatory method.

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

回答by Ayaz Alifov

You can do it in a few lines, just override onPostExecute when you call your AsyncTask. Here is an example for you:

您可以在几行中完成,只需在调用 AsyncTask 时覆盖 onPostExecute。这是一个例子:

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

I hope it helped you, happy codding :)

我希望它对你有帮助,编码愉快:)

回答by user3691697

in your Oncreate():

在您的 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();

}`

}`

回答by nicholas.hauschild

You can call the get()method of AsyncTask(or the overloaded get(long, TimeUnit)). This method will block until the AsyncTaskhas completed its work, at which point it will return you the Result.

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

It would be wise to be doing other work between the creation/start of your async task and calling the getmethod, otherwise you aren't utilizing the async task very efficiently.

在异步任务的创建/启动和调用get方法之间做其他工作是明智的,否则你不能非常有效地利用异步任务。

回答by Kuvalya

You can write your own listener. It's same as HelmiB's answer but looks more natural:

您可以编写自己的侦听器。它与HelmiB的答案相同,但看起来更自然:

Create listener interface:

创建监听器接口:

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

Then write your asynchronous task:

然后编写您的异步任务:

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

Finally implement listener in activity:

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

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
        }        
    }

And this is how you can call asyncTask:

这就是您可以调用 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...
}

回答by bugdayci

Why do people make it so hard.

为什么人要这么难。

This should be sufficient.

这应该足够了。

Do not implement the onPostExecute on the async task, rather implement it on the Activity:

不要在异步任务上实现 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");

}


}