这是一个我不知道该怎么做。基本上,我有一个ASyncTask类,它在后台照常工作。我想在完成后做点什么。现在,在你跳到前面说"只使用 onPostExecute()"之前,有一个问题。我需要运行的方法在活动中,而不是在 Task 类中。
在我看来,我有 2 个选择。
一个:
CustomTask task = new CustomTask();
task.execute(passedParams);
//when(task.execute is finished)
{
doX();
}
我希望我能这样做,因为它非常简单,让我检查任务何时完成,而不必不断轮询它的活动和活动的 getStatus()。我不认为我会这么幸运,但如果有人有办法做到这一点,那就太好了。
乙:
将活动作为参数传递给 ASyncTask。这很混乱,我不高兴使用它,但除了它和对象引用之外,我不知道它是否会起作用
CustomTask task = new CustomTask();
task.execute(passedParams,MyActivity);
然后在 Tasks onPostExecute 中,我可以让它调用 MyActivity.doX();
三:
第三种方法是使异步任务成为活动本身中的私有类,但我真的很想将其分开。可重用性以及什么不是 –
对此有什么想法吗?
总而言之,需要在task.execute完成后doX()。任何想法都值得赞赏。
D:
好的,我知道我在这里滚动。我一直在想新的解决方案。可以从任何位置调用的类方法或静态方法。
public class ProfileSettings extends Activity
{
public static void doX()
{
//Logic...
}
}
从异步任务
MyActivity.doX();
选项 B 应该有效,有时是一个不错的选择,但有时我为此使用匿名类。当您从活动中调用它时:
CustomTask task = new CustomTask() {
@Override
protected void onPostExecute(Long result) {
super.onPostExecute(result);
MyActivity.this.doX();
}
}.execute();
选项 A:
Android API 已经为此提供了内置函数 AsyncTask.get():
CustomTask task = new CustomTask();
task.execute(passedParams);
Result result = task.get(); // <- Block UI thread and waiting for AsyncTask finish.
this.doX(result);
如您所见,这是一种不好的做法,因为它会阻止 UI 线程并可能导致 ANR 异常,通过这样做,您实际上牺牲了 AsyncTask 的好处,并使其与 UI 线程同步运行。
备选方案B和C:
两者都是正确的做事方式,通过在 onPostExecute() 方法中调用 doX() 方法,
顾名思义,AsyncTask与UI线程异步运行后台线程,一旦后台线程完成,就会在UI线程上调用onPostExecute方法。没有办法确切地告诉在项目构建时何时调用onPostExecute方法(即doInBackground方法何时完成),因为它是在应用程序运行时确定的,我们唯一知道的是onPostExecute方法保证在未来的某个时候在UI线程上被调用,换句话说,在项目构建时编写代码时, 我们永远不知道doInBackground何时完成,代码执行何时跳回到onPostExecute方法之外的UI线程(除非您在选项A之类的代码中实现一些等待机制)。所以onPostExecute方法的目的是在doInBackground方法完成后处理所有内容,这也是为什么onPostExecute方法的唯一参数是doInBackground方法返回的结果。
选项 B 和 C 之间的区别在于是将 AsyncTask 实现为内部类还是单独的类。这在StackOverflow中已经被多次讨论和讨论。大多数人认为出于可重用性等原因将它们分开是件好事。从我的角度来看,我不同意。Java编程语言有其理由提供内部类语法以适应一些特殊的编码情况,当从OOP的角度谈论代码重构时,更多地从问题抽象层面考虑,而不是简单地在代码级别从Activity类中剥离内部类。正如您在示例中所看到的,通过将 AsyncTask 与活动隔离,您不会获得任何真正的好处,而是会增加代码复杂性(需要在类之间传递活动上下文引用)来解决问题。
我认为您真正的问题是我们是否应该将 AsyncTask 内部类实现与活动隔离开来。为了更好地重构 OOP 代码(可重用性、可测试性等),请查看我在这个 StackOverflow 问题中的答案,了解如何正确地将业务层与应用程序 UI 层隔离开来。
我能够通过一个接口实现这个功能:
http://howcanisolve.com/38646/android-java-equivalent-of-ios-block-callbacks
public interface ICallbacks {
public void onResponse(JSONObject response);
public void onError(VolleyError error);
}
然后在您的例程代码中,只需放置一个新的回调实例:
public static void getPassagesForFirebaseUser(FirebaseUser user,
Context context, ICallbacks events) {
//here code and call ICallbacks methods
if(result){ events.onResponse(response); }
if(error){ events.onError(err); }
}
最终,您可以使用以下命令调用该方法:
getPassagesForFirebaseUser(user, context, new ICallbacks(){
@Override
public void onResponse(JSONObject response){
//Success !!!
}
@Override
public void onError(VolleyError response){
//Error !!!
}
});
选项 B 通常更安全。但即便如此,你也需要小心。您需要将Activity
(而不仅仅是类)的实例存储在ASyncTask
中。如果Activity
在任务运行时被销毁(如果用户按下"后退"按钮怎么办?),您需要将此通知任务,以便任务不会尝试在死Activity
上调用方法。
如果Activity
恢复活力(例如,在屏幕旋转之后),则需要将新Activity
重新附加到正在运行的任务。
这些东西很繁琐。