在 ASyncTask.execute() 之后,从 Activity 执行 x()



这是一个我不知道该怎么做。基本上,我有一个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重新附加到正在运行的任务。

这些东西很繁琐。

最新更新