小编典典

Android:将函数引用传递给AsyncTask

java

我是android新手,非常习惯于网络开发。在javascript中,当您要执行异步任务时,可以将函数作为参数传递(回调):

http.get('www.example.com' , function(response){
   //some code to handle response
});

我想知道我们是否可以对android进行相同的操作AsyncTask,将函数引用传递给onPostExecute()方法,然后它将运行它。

有什么建议 ?


阅读 222

收藏
2020-10-07

共1个答案

小编典典

是的,回调的概念在Java中也非常存在。在Java中,您可以这样定义一个回调:

public interface TaskListener {
    public void onFinished(String result);
}

人们通常会在AsyncTask这样的内部嵌套这些侦听器定义:

public class ExampleTask extends AsyncTask<Void, Void, String> {

    public interface TaskListener {
        public void onFinished(String result);
    }

    ...
}

回调的完整实现AsyncTask如下所示:

public class ExampleTask extends AsyncTask<Void, Void, String> {

    public interface TaskListener {
        public void onFinished(String result);
    }

    // This is the reference to the associated listener
    private final TaskListener taskListener;

    public ExampleTask(TaskListener listener) {
        // The listener reference is passed in through the constructor
        this.taskListener = listener;
    }

    @Override
    protected String doInBackground(Void... params) {
        return doSomething();
    }

    @Override
    protected void onPostExecute(String result) {
        super.onPostExecute(result);

        // In onPostExecute we check if the listener is valid
        if(this.taskListener != null) {

            // And if it is we call the callback function on it.
            this.taskListener.onFinished(result);
        }
    }
}

onPostExecute()后台任务完成后立即调用。您可以像这样使用整个内容:

ExampleTask task = new ExampleTask(new ExampleTask.TaskListener() {
    @Override
    public void onFinished(String result) {
        // Do Something after the task has finished
    }
});

task.execute();

或者,您可以TaskListener像下面这样完全定义:

ExampleTask.TaskListener listener = new ExampleTask.TaskListener() {
    @Override
    public void onFinished(String result) {
        // Do Something after the task has finished
    }
};

ExampleTask task = new ExampleTask(listener);    
task.execute();

或者,您可以TaskListener像这样子类化:

public class ExampleTaskListener implements TaskListener {

    @Override
    public void onFinished(String result) {

    }
}

然后像这样使用它:

ExampleTask task = new ExampleTask(new ExampleTaskListener());    
task.execute();

当然,您可以覆盖的onPostExecute()方法AsyncTask,但是不建议这样做,在大多数情况下,这实际上是非常糟糕的做法。例如,您可以这样做:

ExampleTask task = new ExampleTask() {
    @Override
    public void onPostExecute(String result) {
        super.onPostExecute(result);

        // Your code goes here
    }
};

这将与上面带有单独的侦听器接口的实现一样好,但是存在一些问题:

首先,您实际上可以将ExampleTask所有内容分解在一起。这一切都归结于super.onPostExecute()上面的电话。如果你作为一个开发人员重写onPostExecute()像上面,却忘了包括超级电话中或者干脆删除它无论出于何种原因,原来onPostExecute()的方法ExampleTask将不再被调用。例如TaskListener,由于对的调用是在中实现的,因此带有的整个侦听器实现将突然不再起作用onPostExecute()。您还可以TaskListener通过不知不觉或无意地影响s的状态来以其他多种方式破坏s的状态ExampleTask

如果您查看重写此类的方法时实际发生的情况,则将比现在更清楚地了解发生了什么。通过覆盖,onPostExecute()您将创建的新子类ExampleTask。这样做完全相同:

public class AnotherExampleTask extends ExampleTask {

    @Override
    public void onPostExecute(String result) {
        super.onPostExecute(result);

        // Your code goes here
    }
}

所有这些都隐藏在称为匿名类的语言功能的后面。突然重载这样的方法似乎不再那么干净快捷了吗?

总结一下:

  • 覆盖这样的方法实际上会创建一个新的子类。您不仅在添加回调,而且还在修改此类的工作方式,并且会在不知不觉中破坏很多东西。
  • 像这样的调试错误可能不仅仅是痛苦中的**。因为突然之间ExampleTask可能由于Exceptions没有明显的原因而抛出或根本无法工作,因为您从未真正修改过它的代码。
  • 每个类都必须在适当和预期的地方提供侦听器实现。当然,您可以稍后通过覆盖将其添加,onPostExecute()但这始终非常危险。甚至@flup以其13k的声誉也忘记了将super.onPostExecute()电话包含在他的答案中,想象一下其他一些没有经验的开发人员会做什么!
  • 一点抽象就不会伤害任何人。编写特定的侦听器可能需要更多代码,但这是一个更好的解决方案。该代码将更简洁,更具可读性且更具可维护性。使用诸如覆盖之类的快捷方式onPostExecute()实际上会牺牲代码质量,从而带来一些便利。这绝不是一个好主意,从长远来看只会造成问题。
2020-10-07