Android 如何将多个原始参数传递给 AsyncTask?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/12069669/
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
How can you pass multiple primitive parameters to AsyncTask?
提问by robguinness
There are related questions, such as How can I pass in 2 parameters to a AsyncTask class? , but I ran into the difficulty of trying in vain to pass multiple primitives as parameters to an AsyncTask, so I want to share what I discovered. This subtlety is not captured in the existing questions and answers, so I want to help out anyone who runs into the same problem as I did and save them the pain.
有相关的问题,例如如何将 2 个参数传递给 AsyncTask 类?,但我遇到了尝试将多个原语作为参数传递给 AsyncTask 的困难,因此我想分享我的发现。这种微妙之处在现有的问题和答案中没有体现出来,所以我想帮助任何和我遇到同样问题的人,让他们免于痛苦。
The question is this: I have multiple primitiveparameters (e.g. two longs) that I want to pass to an AsyncTask to be executed in the background--how can it be done? (My answer...after struggling with this for awhile...can be found below.)
问题是这样的:我有多个原始参数(例如两个 longs),我想将它们传递给要在后台执行的 AsyncTask——怎么做?(我的答案......在为此挣扎了一段时间后......可以在下面找到。)
采纳答案by robguinness
It is (strictly-speaking) NOT possible to pass multiple primitives to AsyncTask. For example, if you want to perform myTask.execute(long1, long2)
and try to set up private class myTask extends AsyncTask<long, Void, Void>
with the corresponding method:
(严格来说)不可能将多个原语传递给 AsyncTask。例如,如果要执行myTask.execute(long1, long2)
并尝试private class myTask extends AsyncTask<long, Void, Void>
使用相应的方法进行设置:
@Override
protected LocationItemizedOverlay doInBackground(long... params) {...}
your IDE will likely complain about needing to override a supertype method. Note that you are using the so-called Varargsmethod signature for doInBackground
, where (long... params)
is like saying "I accept a variable number of longs, stored as an array called params. I don't completely understand what causes a compiler/IDE complaint to be raised, but I think it has to do with how the generic class Params
is defined.
您的 IDE 可能会抱怨需要覆盖超类型方法。请注意,您正在使用所谓的Varargs方法签名 for doInBackground
,(long... params)
就像在说“我接受可变数量的 long,存储为名为 params 的数组。我不完全理解是什么导致编译器/IDE 投诉被提出,但我认为这与泛型类Params
的定义方式有关。
In any case, it is possible to achieve what you want with no problem, provided you correctly cast your primitives to their respective non-primitive wrappers (e.g. int => Integer, long => Long, etc.). Actually, you don't need to explicitly cast your primitives to non-primitives. Java seems to handle that for you. You just need to set up your ASyncTask as follows (for the example of longs):
在任何情况下,只要您正确地将基元转换为它们各自的非基元包装器(例如 int => Integer、long => Long 等),就可以毫无问题地实现您想要的目标。实际上,您不需要将原语显式转换为非原语。Java 似乎可以为您处理。您只需要按如下方式设置 ASyncTask(以 long 为例):
private class MyTask extends AsyncTask<Long, Void, Void> {
@Override
protected void doInBackground(Long... params) {
// Do stuff with params, for example:
long myFirstParam = params[0]
}
...
}
You can then use this class as you originally intended, e.g.:
然后,您可以按照最初的意图使用此类,例如:
MyTask myTask = new MyTask();
myTask.execute(long1, long2);
Or for any number of primitives that you would like, PROVIDED THEY ARE OF THE SAME TYPE. If you need to pass multiple types of primitives, this can also be done, but you will need to modify the above to:
或者对于您想要的任意数量的基元,只要它们是相同的类型。如果您需要传递多种类型的原语,也可以这样做,但您需要将上述内容修改为:
private class MyTask extends AsyncTask<Object, Void, Void> {
@Override
protected void doInBackground(Object... params) {
// Do stuff with params, for example:
long myLongParam = (Long) params[0];
int myIntParam = (Integer) params[1];
}
...
}
This is more flexible, but it requires explicitly casting the parameters to their respective types. If this flexibility is not needed (i.e. a single data type), I recommend sticking to the first option, as it's slightly more readable.
这更灵活,但它需要明确地将参数转换为它们各自的类型。如果不需要这种灵活性(即单一数据类型),我建议坚持使用第一个选项,因为它稍微更具可读性。
回答by David Wasser
Just wrap your primitives in a simple container and pass that as a parameter to AsyncTask
, like this:
只需将您的原语包装在一个简单的容器中并将其作为参数传递给AsyncTask
,如下所示:
private static class MyTaskParams {
int foo;
long bar;
double arple;
MyTaskParams(int foo, long bar, double arple) {
this.foo = foo;
this.bar = bar;
this.arple = arple;
}
}
private class MyTask extends AsyncTask<MyTaskParams, Void, Void> {
@Override
protected void doInBackground(MyTaskParams... params) {
int foo = params[0].foo;
long bar = params[0].bar;
double arple = params[0].arple;
...
}
}
Call it like this:
像这样调用它:
MyTaskParams params = new MyTaskParams(foo, bar, arple);
MyTask myTask = new MyTask();
myTask.execute(params);
回答by malajisi
Another way: You just need add MyTask constructor in your MyTask class:
另一种方法:您只需要在 MyTask 类中添加 MyTask 构造函数:
private class MyTask extends AsyncTask<String, Void, Void> {
int foo;
long bar;
double arple;
MyTask(int foo, long bar, double arple) {
// list all the parameters like in normal class define
this.foo = foo;
this.bar = bar;
this.arple = arple;
}
...... // Here is doInBackground etc. as you did before
}
Then call
然后打电话
new MyTask(int foo, long bar, double arple).execute();
A second way like David Wasser's Answer.
第二种方式,如 David Wasser 的回答。
回答by Speckpgh
The built in execute method accepts an array of Params, but they all must be of the defined type.. so if you simply set the PARAMtype to OBJECT, then you can pass in whatever you like as long as they are children of objects....
内置的 execute 方法接受一个Params数组,但它们都必须是定义的类型..所以如果你简单地将PARAM类型设置为OBJECT,那么你可以传入任何你喜欢的东西,只要它们是对象的子对象。 ...
private class MyTask extends AsyncTask<Object, Void, Void> {
Then in your doInBackGround, you simply cast each param in order back to what you need it to be:
然后在 doInBackGround 中,您只需将每个参数转换为您需要的值:
@Override
protected void doInBackground(Object... params) {
Context t = (Context)params[0];
String a = (String) params[1];
List<LatLng> list = (List<LatLng>)params[2];
.
.
.
And your execute is simply:
你的执行很简单:
new MyTask().execute(context,somestring,list_of_points);
Not as good form as wrapping it in your own wrapper class, or a bundle, or hash or something, because you are order dependent on both sides, but it will work. Of course you could just make your array a param of HashMap(,) and you basically are custom implementing a bundle at that point, but it will work.
不如将它包装在你自己的包装类、包、散列或其他东西中那样好,因为你依赖于双方的顺序,但它会起作用。当然,你可以让你的数组成为 HashMap(,) 的参数,并且你基本上是在那时自定义实现一个包,但它会起作用。
回答by MrPlow
I like malajisi's method, but if you didn't, couldn't you use the Bundle class?
我喜欢malajisi的方法,但如果你不喜欢,你就不能使用Bundle类吗?
Bundle myBundle = new Bundle();
myBundle.putInt("foo", foo);
myBundle.putLong("bar", bar);
myBundle.putDouble("arple", arple);
Then just pass the bundle and unpack it inside MyTask. Is this a terrible idea? You avoid creating a custom class, and it's flexible if you decide you need to pass additional parameters later.
然后只需传递包并将其解压缩到 MyTask 中。这是一个可怕的想法吗?您可以避免创建自定义类,并且如果您决定稍后需要传递其他参数,它会很灵活。
Update: It has been quite a few years since I wrote this answer, and I really dislike it now. I would recommend against using a Bundle. If you need to pass multiple parameters into an asynctask (or anything, really), use a custom class that holds all your parameters at once. Using a bundle is a fine solution to a problem you shouldn't have. There is no law against creating a custom class to hold exactly what you need, and nothing else.
更新:我写这个答案已经好几年了,现在我真的不喜欢它。我建议不要使用 Bundle。如果您需要将多个参数传递给 asynctask(或任何东西,真的),请使用一次保存所有参数的自定义类。使用捆绑包是解决您不应该遇到的问题的好方法。没有任何法律禁止创建自定义类来保存您所需要的内容,仅此而已。
Also, why aren't you using coroutines? Asynctasks are so2014.
另外,你为什么不使用协程?异步任务是如此2014。
回答by Bijan
This is solved via subclassing. Google has an example for solving this problem (subclassing) in the official Android AsyncTask Documentation:
这是通过子类化解决的。谷歌在官方的Android AsyncTask 文档中有一个解决这个问题的例子(子类化):
http://developer.android.com/reference/android/os/AsyncTask.html
http://developer.android.com/reference/android/os/AsyncTask.html
Example:
例子:
private class DownloadFilesTask extends AsyncTask<URL, Integer, Long> {
protected Long doInBackground(URL... urls) {
int count = urls.length;
long totalSize = 0;
for (int i = 0; i < count; i++) {
totalSize += Downloader.downloadFile(urls[i]);
publishProgress((int) ((i / (float) count) * 100));
// Escape early if cancel() is called
if (isCancelled()) break;
}
return totalSize;
}
protected void onProgressUpdate(Integer... progress) {
setProgressPercent(progress[0]);
}
protected void onPostExecute(Long result) {
showDialog("Downloaded " + result + " bytes");
}
}