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
How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class?
提问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:
简单:
Create
interface
class, whereString output
is optional, or can be whatever variables you want to return.public interface AsyncResponse { void processFinish(String output); }
Go to your
AsyncTask
class, and declare interfaceAsyncResponse
as a field :public class MyAsyncTask extends AsyncTask<Void, Void, String> { public AsyncResponse delegate = null; @Override protected void onPostExecute(String result) { delegate.processFinish(result); } }
In your main Activity you need to
implements
interfaceAsyncResponse
.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
类, whereString output
是可选的,或者可以是你想要返回的任何变量。public interface AsyncResponse { void processFinish(String output); }
转到您的
AsyncTask
类,并将接口声明AsyncResponse
为字段:public class MyAsyncTask extends AsyncTask<Void, Void, String> { public AsyncResponse delegate = null; @Override protected void onPostExecute(String result) { delegate.processFinish(result); } }
在您的主 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 AsyncTask
class.
仍在使用相同的interface
. 仅供参考,您可以将其合并到AsyncTask
课程中。
in AsyncTask
class :
在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 Activity
class
在你的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 result
to different matching types in order to get different objects.
提示:将String output
、String response
、 和更改String result
为不同的匹配类型以获得不同的对象。
回答by quietmint
There are a few options:
有几个选项:
Nest the
AsyncTask
class within yourActivity
class. 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
AsyncTask
that takes a reference to yourActivity
. You would instantiate the task with something likenew 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 Activity
dependent 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 Activity
or interface
always use weakreference in those cases.
这个答案可能晚了,但当你Activity
依赖AsyncTask
. 这将帮助您防止崩溃和内存管理。正如在上面的答案中已经提到的那样interface
,我们也说它们是回调。他们将作为告密者工作,但在这些情况下永远不会发送强引用Activity
或interface
始终使用弱引用。
Please refer to below screenshot to findout how that can cause issues.
请参阅下面的屏幕截图以了解如何导致问题。
As you can see if we started AsyncTask
with a strongreference then there is no guarantee that our Activity
/Fragment
will be alive till we get data, so it would be better to use WeakReference
in those cases and that will also help in memory management as we will never hold the strong reference of our Activity
then 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.java
Interface which will work as an informer.
MyTaskInformer.java
将作为告密者工作的界面。
public interface MyTaskInformer {
void onTaskDone(String output);
}
MySmallAsyncTask.java
AsyncTask to do long running task, which will use WeakReference
.
MySmallAsyncTask.java
AsyncTask 执行长时间运行的任务,它将使用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
This class is used to start my AsyncTask
implement interface
on this class and override
this mandatory method.
MainActivity.java
这个类用于在这个类和这个强制方法上启动我的AsyncTask
实现。interface
override
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 AsyncTask
has 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 get
method, 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");
}
}