java Android:将函数引用传递给 AsyncTask
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26202568/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Android: pass function reference to AsyncTask
提问by user47376
I'm new to android and very used to web developing. in javascript when you want to perform an asynchronous task you pass a function as an argument (a callback):
我是 android 新手,非常习惯于 web 开发。在 javascript 中,当您想要执行异步任务时,您可以将函数作为参数(回调)传递:
http.get('www.example.com' , function(response){
//some code to handle response
});
I was wondering if we can do the same with android's AsyncTask
, pass a function reference to the onPostExecute()
method , and it will run it.
我想知道我们是否可以对 android 做同样的事情AsyncTask
,将函数引用传递给onPostExecute()
方法,然后它就会运行它。
any suggestions ?
有什么建议 ?
回答by Xaver Kapeller
Yes the concept of callbacks also very much exists in Java. In Java you define a callback like this:
是的,Java 中也大量存在回调的概念。在 Java 中,您可以像这样定义回调:
public interface TaskListener {
public void onFinished(String result);
}
One would often nest these kind of listener definitions inside the AsyncTask
like this:
人们通常会在AsyncTask
这样的内部嵌套这些类型的侦听器定义:
public class ExampleTask extends AsyncTask<Void, Void, String> {
public interface TaskListener {
public void onFinished(String result);
}
...
}
And a complete implementation of the callback in the AsyncTask
would look like this:
中回调的完整实现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()
is called as soon as the background task finishes. You can use the whole thing like this:
onPostExecute()
后台任务完成后立即调用。你可以像这样使用整个东西:
ExampleTask task = new ExampleTask(new ExampleTask.TaskListener() {
@Override
public void onFinished(String result) {
// Do Something after the task has finished
}
});
task.execute();
Or you can define the TaskListener
completely separately like this:
或者你可以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();
Or you can subclass TaskListener
like this:
或者你可以TaskListener
像这样子类化:
public class ExampleTaskListener implements TaskListener {
@Override
public void onFinished(String result) {
}
}
And then use it like this:
然后像这样使用它:
ExampleTask task = new ExampleTask(new ExampleTaskListener());
task.execute();
You can of course just override the onPostExecute()
method of the AsyncTask
, but that is not recommended and in most cases actually pretty bad practice. For example you could do this:
您当然可以只覆盖 的onPostExecute()
方法AsyncTask
,但不推荐这样做,并且在大多数情况下实际上是非常糟糕的做法。例如你可以这样做:
ExampleTask task = new ExampleTask() {
@Override
public void onPostExecute(String result) {
super.onPostExecute(result);
// Your code goes here
}
};
This will work just as well as the implementation above with a separate listener interface, but there are a few problems with this:
这将与上面使用单独侦听器接口的实现一样有效,但存在一些问题:
First and foremost you can actually break the ExampleTask
all together. It all comes down to the super.onPostExecute()
call above. If you as a developer override onPostExecute()
like above and forget to include the super call or simply delete it for whatever reason that the original onPostExecute()
method in the ExampleTask
will not be called anymore. For example the whole listener implementation with the TaskListener
would suddenly not work anymore since the call to the callback is implemented in onPostExecute()
. You can also break the TaskListener
in many other ways by unknowingly or unwittingly influencing the state of the ExampleTask
so it won't work anymore.
首先也是最重要的,你实际上可以打破ExampleTask
所有的一切。这一切都归结为super.onPostExecute()
上面的调用。如果您作为开发人员覆盖onPostExecute()
上述内容并忘记包含超级调用,或者出于任何原因将其删除,否则将不再调用中的原始onPostExecute()
方法ExampleTask
。例如TaskListener
,由于对回调的调用是在onPostExecute()
. 您还可以TaskListener
通过不知不觉或不知不觉地影响 的状态以许多其他方式破坏 ,ExampleTask
使其不再起作用。
If you look at what's actually happening when you override a method like this than it becomes much more clear what's going on. By overriding onPostExecute()
you are creating a new subclass of ExampleTask
. It would be the exact same thing as doing this:
如果你看看当你重写这样的方法时实际发生了什么,那么发生的事情就会变得更加清楚。通过覆盖,onPostExecute()
您正在创建ExampleTask
. 这将与执行此操作完全相同:
public class AnotherExampleTask extends ExampleTask {
@Override
public void onPostExecute(String result) {
super.onPostExecute(result);
// Your code goes here
}
}
All this is just hidden behind a language feature called anonymous classes. Suddenly overriding a method like this doesn't seem so clean and quick anymore does it?
所有这些都隐藏在称为匿名类的语言功能后面。突然覆盖这样的方法似乎不再那么干净和快速了,是吗?
To summarise:
总结一下:
- Overriding a method like this actually creates a new subclass. You are not just adding a callback, you are modifying how this class works and can unknowingly break oh so many things.
- Debugging errors like this can be much more than just a pain in the a**. Because suddenly
ExampleTask
could throwExceptions
or simply not work anymore for no apparent reason, because you never actually modified its code. - Each class has to provide listener implementations at places where it is appropriate and intended. Sure you can just add them later on by overriding
onPostExecute()
but that is always very dangerous. Even @flup with his 13k reputation has forgotten to include thesuper.onPostExecute()
call in his answer, imagine what some other not as experienced developer might do! - A little abstraction never hurt anybody. Writing specific listeners might be slightly more code, but it is a much better solution. The code will be cleaner, more readable and a lot more maintainable. Using shortcuts like overriding
onPostExecute()
essentially sacrifices code quality for a little bit convenience. That is never a good idea an will just cause problems in the long run.
- 覆盖这样的方法实际上会创建一个新的子类。你不仅仅是添加一个回调,你正在修改这个类的工作方式,并且可能会在不知不觉中破坏很多东西。
- 像这样的调试错误不仅仅是在 a** 中的痛苦。因为突然
ExampleTask
可以Exceptions
无缘无故地抛出或根本不再工作,因为你从未真正修改过它的代码。 - 每个类都必须在适当和预期的地方提供侦听器实现。当然,您可以稍后通过覆盖来添加它们,
onPostExecute()
但这总是非常危险的。甚至拥有 13k 声誉的 @flup 也忘记super.onPostExecute()
在他的回答中包含电话,想象一下其他一些没有经验的开发人员可能会做什么! - 一点抽象永远不会伤害任何人。编写特定的侦听器可能会稍微多一些代码,但这是一个更好的解决方案。代码将更清晰、更易读且更易于维护。使用像覆盖这样的快捷方式
onPostExecute()
本质上牺牲了代码质量以获得一点便利。这绝不是一个好主意,从长远来看只会引起问题。
回答by flup
In Java, functions are less of a first class citizen than in JavaScript. The AsyncTask provides the callback as a method in the class, which you should override.
在 Java 中,函数不像在 JavaScript 中那样是一等公民。AsyncTask 提供回调作为类中的方法,您应该覆盖它。
See Make an HTTP request with androidfor a subclass of AsyncTask with an implementation of the doInBackground which makes a web request.
请参阅Make an HTTP request with androidfor a subclass of AsyncTask with an implementation of the doInBackground which make a web request.
If you want to do multiple HTTP requests with different callbacks, you can override RequestTask and implement onPostExecute with the different callback implementations. You can use an anonymous class to simulate the closure a JavaScript callback commonly uses:
如果要使用不同的回调执行多个 HTTP 请求,可以覆盖 RequestTask 并使用不同的回调实现实现 onPostExecute。您可以使用匿名类来模拟 JavaScript 回调常用的闭包:
new RequestTask(){
@Override
public void onPostExecute(String result) {
// Implementation has read only access to
// final variables in calling scope.
}
}.execute("http://stackoverflow.com");
As Xaver shows, you can also create a full-blown interface for the listener. This seems only useful to me if you wish to implement a couple default onPostExecute functions and pick one of these default implementations for a particular call.
正如 Xaver 所示,您还可以为侦听器创建一个完整的界面。如果您希望实现几个默认的 onPostExecute 函数并为特定调用选择这些默认实现中的一个,这似乎对我有用。
回答by Sup.Ia
in Kotlin
在科特林
Firstly, create class AsyncTaskHelper as below.
首先,创建类 AsyncTaskHelper 如下。
class AsyncTaskHelper() : AsyncTask<Callable<Void>, Void, Boolean>() {
var taskListener: AsyncListener? = null
override fun doInBackground(vararg params: Callable<Void>?): Boolean {
params.forEach {
it?.call()
}
return true
}
override fun onPreExecute() {
super.onPreExecute()
}
override fun onPostExecute(result: Boolean?) {
super.onPostExecute(result)
taskListener?.onFinished(result as Any)
}
}
interface AsyncListener {
fun onFinished(obj: Any)
}
the code below you can use when you want to use async task.
当您想使用异步任务时,您可以使用下面的代码。
AsyncTaskHelper().let {
it.execute(Callable<Void> {
//this area is the process do you want to do it in background
// dosomething()
}
}
null
})
it.taskListener = object : AsyncListener{
override fun onFinished(obj: Any) {
// this area is for the process will want do after finish dosomething() from Callable<Void> callback
}
}
From the code above. if you want to separate your process to several task. you can do as this code below.
从上面的代码。如果您想将您的流程分成几个任务。您可以按照下面的代码进行操作。
AsyncTaskHelper().let {
it.execute(Callable<Void> {
// task 1 do in background
null
},Callable<Void>{
// task 2 do in background
null
},Callable<Void>{
// task 3 do in background
null
})
it.taskListener = object : AsyncListener {
override fun onFinished(obj: Any) {
// when task1,task2,task3 has been finished . it will do in this area
}
}
}