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

时间:2012-04-11 23:09:42

标签: java android multithreading android-activity android-asynctask

这是一个我不确定如何去做的人。 基本上我有一个ASyncTask类,它在后台照常开展业务。我想在完成后做点什么。现在,在你跳到前面并说'#34;只需使用onPostExecute()"之后,就会有一个问题。我需要运行的方法是在activity而不是Task类。

我看到它的方式,我有两个选择。

A:

    CustomTask task = new CustomTask();
    task.execute(passedParams);
            //when(task.execute is finished)
            {
                doX();
            }

我希望我可以这样做,因为它非常简单,让我检查任务何时完成,而不必经常轮询活动和getStatus()活动。 我不认为我会幸运,但如果有人有办法,那就太棒了

B:

将活动作为参数传递给ASyncTask。这很乱,我对使用它不满意,但除了那个和对象参考,我不知道它是否会起作用

    CustomTask task = new CustomTask();
    task.execute(passedParams,MyActivity);

然后在Tasks onPostExecute中,我可以让它调用MyActivity.doX();


C:

第三种方法是使asynctask成为活动本身的私有类,但我真的希望将它保持独立。可重复性和什么不 -

对此有何想法?

总结一下,在task.execute完成后需要doX()。任何想法都赞赏。


d

好的,我知道我在这里滚动。我一直在想新的解决方案。可以从任何位置调用的类方法或静态方法。

public class ProfileSettings extends Activity
{
      public static void doX()
      {
          //Logic...
      }
}

来自AsyncTask

MyActivity.doX();

4 个答案:

答案 0 :(得分:6)

选项B应该有效,有时是一个不错的选择,但有时我会使用匿名类。当您从活动中调用它时:

CustomTask task = new CustomTask() {
    @Override
    protected void onPostExecute(Long result) {
        super.onPostExecute(result);
        MyActivity.this.doX();
    }
}.execute();

答案 1 :(得分:2)

选项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线程(除非你在代码中实现一些等待机制,如Option一个)。因此onPostExecute方法的目的是在doInBackground方法完成后处理所有内容,这也是为什么onPostExecute方法的唯一参数是doInBackground方法返回的结果。

选项B和C之间的区别在于是将AsyncTask实现为内部类还是单独的类。这已在StackOverflow中多次讨论和讨论过。大多数人认为将它们分开以获得可重复使用的原因是好的。从我的观点来看,我不同意它。 Java编程语言有其原因提供内部类语法以适应某些特殊的编码情况,当从OOP角度讨论代码重构时,更多地考虑问题抽象级别,而不是简单地从代码级别的Activity类中删除内部类。正如您在示例中所看到的,通过将AsyncTask与Activity隔离,您不会获得任何实际好处,而是增加代码复杂性(需要在类之间传递活动上下文引用)来解决问题。

我认为你真正的问题是我们是否应该从Activity中隔离AsyncTask内部类实现。要获得更好的OOP代码重构(可重用性,可测试性等),请在此StackOverflow question中查看我的答案,了解如何正确地将业务层与应用程序UI层隔离。

答案 2 :(得分:1)

我能够通过界面实现此功能:

http://howcanisolve.com/38646/android-java-equivalent-of-ios-block-callbacks

public interface ICallbacks { 
public void onResponse(JSONObject response);
public void onError(VolleyError error);
}

然后在您的例程代码中添加一个新的Callbacks实例:

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

答案 3 :(得分:0)

选项B通常更安全。但即便如此,你还需要小心。您需要在Activity中存储ASyncTask(不仅仅是类)的实例。如果Activity在任务运行时被破坏(如果用户按下后退按钮怎么办?),则需要通知任务,以便任务不会尝试在死亡Activity上调用方法。

如果Activity恢复生机(例如,在屏幕旋转后),则需要将新Activity重新附加到正在运行的任务中。

这些事情很繁琐。