由于 AsyncTask 是一个单独的类,如何将 OnPostExecute() 的结果获取到主要活动?
Posted
技术标签:
【中文标题】由于 AsyncTask 是一个单独的类,如何将 OnPostExecute() 的结果获取到主要活动?【英文标题】:How to get the result of OnPostExecute() to main activity because AsyncTask is a separate class? 【发布时间】:2012-09-16 12:07:35 【问题描述】:我有这两个课程。我的主要活动和扩展AsyncTask
的活动,现在在我的主要活动中,我需要从AsyncTask
中的OnPostExecute()
获取结果。如何将结果传递或获取到我的主 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);
这是 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-local-broadcast-receiver 为什么不用观察者模式? 【参考方案1】:简单:
创建interface
类,其中String 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);
在您的主要活动中,您需要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个解决方案,第一个和第三个,需要创建方法processFinish
,另一个,方法在caller参数里面。第三个更整洁,因为没有嵌套的匿名类。
提示:将String output
、String response
、String result
更改为不同的匹配类型,以获得不同的对象。
【讨论】:
完全写了所有这些,然后看到了你的答案:) 这是相同的想法! +1。同样这样多个东西可以监听 AsyncTask 的结果! 我收到空指针异常,因为委托设置为空,请清除它 对.net 开发人员的说明,可以使用 AutoResetEvents 来实现这一点,还有一个用于 autoresetevents 的 java 实现,但这更简洁。顺便问一下,ProcessFinish 线程安全吗? 对于所有获得空指针的人,将您的接口传递给您的 asyncTask 类构造函数,然后将其分配给一个变量,然后对该变量调用 processfinish()。作为参考,请参阅接受的答案。 ***.com/questions/9963691/… @Sunny 你是对的......另外,我们必须为 async.delegate = this 初始化异步对象;上班..【参考方案2】:有几个选项:
将AsyncTask
类嵌套在您的Activity
类中。假设您不在多个活动中使用相同的任务,这是最简单的方法。您的所有代码都保持不变,您只需将现有任务类移动为 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
,为什么还要经历构造函数和字段的痛苦?只需使用来自MyActivity
或MyActivity.this.fieldOrMethod
的任何fieldOrMethod
(如果有阴影)。
@TWiStErRob 第二个假设MyAsyncTask
不是内部类。
哦,对不起,private
/protected
不允许用于***课程,因此我认为它必须是非static
内部课程。
请注意内部类 AsyncTask 可能是内存泄漏的来源,如此处所述garena.github.io/blog/2014/09/10/android-memory-leaks
持有 Activity 引用也是内存泄漏。回调的方式远比这个好【参考方案3】:
我觉得下面的方法很简单。
我已经声明了回调接口
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.." );
);
谢谢
【讨论】:
【参考方案4】:您可以在 Main 类中尝试此代码。 这对我有用,但我以其他方式实现了方法
try
String receivedData = new AsyncTask().execute("http://yourdomain.com/yourscript.php").get();
catch (ExecutionException | InterruptedException ei)
ei.printStackTrace();
【讨论】:
你能解释一下为什么这会帮助 OP 解决他们的问题吗? 这对我有帮助。我尝试了其他方式,例如@HelmiB 的答案,但我没有得到任何结果 好的对不起我的回答。她需要调用 AsyncTask 类,然后给这个调用放一个参数。 AsyncTask 由 3 种通用类型定义:1 参数(服务器域或其他参数) 2 进度(可以为 void),3 结果。所有这些类型都可以是:JSONObject、字符串或任何数据类型。当你有一个 AsyncTask 类时,你应该定义将数据发送到哪里。例如:asyncTask.execute("sampletargeturl.com").get(); 使用此方法时,我在 Logcat 上收到警告:“我/Choreographer:跳过 50 帧!应用程序可能在其主线程上做太多工作。”如何处理?等待从 AsyncTask 返回时 UI 是否会冻结? @NicuP 你可能忘了打电话给execute()
,看看我的回答,我已经在那里添加了评论。你可能想检查我更新的答案。希望这会有所帮助。【参考方案5】:
这个答案可能会迟到,但是当您的 Activity
依赖于 AsyncTask
时,我想提几点。这将帮助您防止崩溃和内存管理。正如上面已经提到的答案与interface
一样,我们也称它们为回调。他们将作为告密者工作,但绝不会发送Activity
或interface
的strong 参考,在这些情况下始终使用weak 参考。
请参阅下面的屏幕截图以了解这会如何导致问题。
如您所见,如果我们以 strong 引用开始 AsyncTask
,则无法保证我们的 Activity
/Fragment
在我们获得数据之前会一直存在,所以它会是在这些情况下最好使用WeakReference
,这也将有助于内存管理,因为我们永远不会持有Activity
的强引用,那么它将在其失真后有资格进行垃圾收集。
查看下面的代码 sn-p 了解如何使用很棒的 WeakReference -
MyTaskInformer.java
接口,将用作告密者。
public interface MyTaskInformer
void onTaskDone(String output);
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
这个类用来启动我的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);
【讨论】:
【参考方案6】:您可以在几行内完成,只需在调用 AsyncTask 时覆盖 onPostExecute。下面是一个例子:
new AasyncTask()
@Override public void onPostExecute(String result)
// do whatever you want with result
.execute(a.targetServer);
希望对你有所帮助,编码愉快:)
【讨论】:
它对我不起作用。它只是没有进入onPostExecute
方法。【参考方案7】:
在你的 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();
`
【讨论】:
【参考方案8】:为什么人们把它弄得这么难。
这应该足够了。
不要在异步任务上实现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
吗?
没有。 @Override 只是一个注解。因此,您是在告诉 java 编译器您打算覆盖该方法并在不这样做时得到通知。【参考方案9】:
您可以调用AsyncTask
(或重载的get(long, TimeUnit)
)的get()
方法。此方法将阻塞,直到 AsyncTask
完成其工作,此时它将返回您 Result
。
在创建/启动异步任务和调用 get
方法之间做其他工作是明智之举,否则您不会非常有效地利用异步任务。
【讨论】:
被否决的 vecause get() 将阻塞主线程。如果 AsyncTask 会阻塞,没有理由使用它【参考方案10】:您可以编写自己的侦听器。和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);
最后在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
这就是你可以调用 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...
【讨论】:
【参考方案11】:嗨,你可以做这样的事情:
创建实现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");
在主活动中添加
// 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();
...
【讨论】:
【参考方案12】:在您的 Activity 类中创建一个静态成员。然后在onPostExecute
期间赋值
例如,如果您的 AsyncTask 的结果是一个字符串,则在您的 Activity 中创建一个公共静态字符串
public static String dataFromAsyncTask;
然后,在 AsyncTask 的 onPostExecute
中,只需对您的主类进行静态调用并设置值。
MainActivity.dataFromAsyncTask = "result blah";
【讨论】:
这种情况下内存泄漏的可能性有多大?【参考方案13】:我通过使用线程和处理程序/消息使其工作。 步骤如下: 声明进度对话框
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();
【讨论】:
【参考方案14】:您需要使用"protocols"来委托或提供数据给AsynTask
。
委托和数据源
委托是一个对象,当该对象遇到程序中的事件时,该对象代表另一个对象或与该对象协作。 (Apple definition)
协议是定义一些方法来委托某些行为的接口。
Here is a complete example!!!
【讨论】:
【参考方案15】:试试这个:
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");
【讨论】:
【参考方案16】:可能有点过火,但我为执行代码和结果提供了回调。显然,为了线程安全,您需要小心在执行回调中访问的内容。
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);
【讨论】:
【参考方案17】:希望你通过this,如果没有请阅读。
https://developer.android.com/reference/android/os/AsyncTask
根据结果数据的性质,您应该选择您能想到的最佳选项。
使用界面
是个不错的选择其他一些选择是..
如果 AsyncTask 类是在您想要的类中定义的 使用结果。使用 static 全局变量或 get() ,从 外部类(volatile 变量,如有必要)。但应该知道 AsyncTask progress 或者至少应该确保它已经完成了任务并且结果是 可通过全局变量 / get() 方法获得。你可以使用 轮询、onProgressUpdate(Progress...)、同步或接口(哪个最适合您)
如果 Result 与 sharedPreference 条目兼容,或者可以保存为内存中的文件,您甚至可以 保存 后台任务本身,可以使用 onPostExecute() 方法 当结果在内存中可用时得到通知。
如果字符串足够小,并且要与 活动。可以在其中使用 intents (putExtra()) onPostExecute() ,但请记住 静态上下文并不那么安全 处理。
如果可能,您可以从 onPostExecute() 方法,结果是你的参数
【讨论】:
以上是关于由于 AsyncTask 是一个单独的类,如何将 OnPostExecute() 的结果获取到主要活动?的主要内容,如果未能解决你的问题,请参考以下文章
如果我有一个扩展的单独的类,如何从onPostExecute()获取值 类?