当前位置: 首页 > 面试题库 >

Android:将函数引用传递给AsyncTask

屈博
2023-03-14
问题内容

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

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

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

有什么建议 ?


问题答案:

是的,回调的概念在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()实际上会牺牲代码质量,从而带来一些便利。这绝不是一个好主意,从长远来看只会造成问题。


 类似资料:
  • 问题内容: 考虑一个非fx的现有应用程序,将其称为。 公开一个对象,该对象又公开了一些属性。也接受这些属性的侦听器。 我的问题是关于 将 JavaFx gui 添加 到此类应用程序。将明显延长,将需要一个参考对象。 在寻找将非String参数传递给我的解决方案时,我发现了几种不同的方法: 静态方法:例如,已初始化对in 的静态引用。在这里可以看到使用静电的一个示例。 JavaFx 9方法:如此处所

  • 问题内容: 我有一个C函数声明如下: 如今,我的cython包装器代码使用了numpy数组中的缓冲区语法: 我想使用新的memoryview语法,我的问题是,使用memoryview时如何将指针传递给数据? 我试过了: 当我尝试编译模块时,出现了“无法将类型’long [:]’分配给’long *’”的错误。有没有什么方法可以在调用C函数之前将指针传递给numpy数组而不将其强制转换为numpy数

  • 要将数组参数传递给函数,需指定不带方括号的数组名。例如,如果数组hourlyTemperatures声明如下: int hourlyTemperatures[24]; 则下列函数调用语句: modifyArray(hourlyTemperatutes,24); 将数组 hourlyTemperatures 及其长度传递给函数 modifyArray。将数组传递给函数时,通常也将其长度传递给函数,使

  • 问题内容: 我有一个用Java实现的javascript接口,该接口由Web视图中加载的javascript代码调用。 JS Inside webview: Java: 通过webview加载的字符串最终是: 我有一些想法: 一个。在JS中以字符串形式构建回调。 b。在将回调传递给Android.myFunction()之前,先调用回调的toString(); 我的问题是,最好的方法是什么?我希望

  • 问题内容: 我希望一个长时间运行的进程通过一个队列(或类似的东西)返回其进度,该队列将被馈送到进度栏对话框。该过程完成后,我还需要结果。这里的测试示例以失败。 我已经能够得到这个使用单独的进程对象的工作(在这里我 很 alowed传递一个队列引用),但是我没有一个池来管理许多过程我想推出。有什么更好的模式建议吗? 问题答案: 以下代码似乎有效: 请注意,队列是从manager.Queue()而不是

  • 我很好奇在Spark中把一个RDD传递给一个函数到底做了什么。 假设我们如上定义一个函数。当我们调用函数并传递一个现有的RDD[String]对象作为输入参数时,这个my_function是否将这个RDD作为函数参数进行“复制”?换句话说,是按引用调用还是按值调用?