是的,回调的概念在 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();
您当然可以只覆盖AsyncTask 的onPostExecute() 方法,但不建议这样做,而且在大多数情况下实际上是非常糟糕的做法。例如,您可以这样做:
ExampleTask task = new ExampleTask() {
@Override
public void onPostExecute(String result) {
super.onPostExecute(result);
// Your code goes here
}
};
这与上面使用单独的侦听器接口的实现一样有效,但存在一些问题:
首先,您实际上可以将ExampleTask 全部破解。这一切都归结为上面的super.onPostExecute() 电话。如果您作为开发人员像上面那样覆盖 onPostExecute() 并忘记包含超级调用,或者出于任何原因将其删除,那么 ExampleTask 中的原始 onPostExecute() 方法将不再被调用。例如,使用TaskListener 的整个侦听器实现将突然不再工作,因为对回调的调用是在onPostExecute() 中实现的。您还可以通过许多其他方式破坏TaskListener,在不知不觉中或无意中影响ExampleTask 的状态,使其不再起作用。
如果您在重写这样的方法时查看实际发生的情况,就会更清楚发生了什么。通过覆盖onPostExecute(),您正在创建ExampleTask 的新子类。这与执行此操作完全相同:
public class AnotherExampleTask extends ExampleTask {
@Override
public void onPostExecute(String result) {
super.onPostExecute(result);
// Your code goes here
}
}
所有这些都隐藏在称为匿名类的语言功能后面。突然覆盖这样的方法似乎不再那么干净和快速了,是吗?
总结:
- 重写这样的方法实际上会创建一个新的子类。您不仅添加了回调,还修改了此类的工作方式,并且可能会在不知不觉中破坏很多东西。
- 像这样的调试错误可能不仅仅是一个痛苦的问题。因为突然间
ExampleTask 可能会抛出Exceptions 或者只是无缘无故地不再工作,因为你从未真正修改过它的代码。
- 每个类都必须在适当和预期的地方提供侦听器实现。当然,您可以稍后通过覆盖
onPostExecute() 来添加它们,但这总是非常危险的。即使是享有 13k 声誉的 @flup 也忘记在他的回答中包含 super.onPostExecute() 电话,想象一下其他没有经验的开发人员可能会做什么!
- 一点抽象永远不会伤害任何人。编写特定的侦听器可能需要更多的代码,但这是一个更好的解决方案。代码将更干净、更易读、更易于维护。使用诸如覆盖
onPostExecute() 之类的快捷方式本质上会牺牲代码质量以获得一点便利。这绝不是一个好主意,从长远来看只会导致问题。