如何向 AsyncTask 传递多个基元参数?

还有一些相关的问题,比如 如何向 AsyncTask 类传入2个参数?,但是我在尝试将多个原语作为参数传递给 AsyncTask 时遇到了困难,所以我想分享我的发现。现有的问题和答案没有体现出这种微妙之处,所以我想帮助那些和我遇到同样问题的人,让他们免受痛苦。

问题是: 我有多个 原始参数(例如两个 long) ,我想要传递给一个在后台执行的 AsyncTask ——如何做到这一点?(我的答案... 经过一段时间的挣扎... 可以在下面找到。)

99983 次浏览

(严格地说)不可能将多个原语传递给 AsyncTask。例如,如果您想执行 myTask.execute(long1, long2)并尝试使用相应的方法设置 private class myTask extends AsyncTask<long, Void, Void>:

@Override
protected LocationItemizedOverlay doInBackground(long... params) {...}

您的 IDE 可能会抱怨需要重写超类型方法。注意,您正在为 doInBackground使用所谓的 瓦拉格方法签名,其中 (long... params)类似于说“我接受一个长度可变的数字,存储为一个名为 params 的数组。我不完全理解是什么导致了编译器/IDE 的抱怨,但是我认为这与泛型类 Params的定义有关。

在任何情况下,只要正确地将原语转换为它们各自的非原语包装器(例如,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]
}
...
}

然后您可以按照最初的设想使用这个类,例如:

MyTask myTask = new MyTask();
myTask.execute(long1, long2);

或者对于任意数量的原语,如果它们是同一类型的话。如果需要传递多种类型的基元,也可以这样做,但是需要将上面的代码修改为:

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];


}
...
}

这更加灵活,但是需要显式地将参数强制转换为它们各自的类型。如果不需要这种灵活性(例如,单个数据类型) ,我建议坚持第一个选项,因为它稍微更具可读性。

只需将原语包装在一个简单的容器中,并将其作为参数传递给 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;
...
}
}

这么说吧:

MyTaskParams params = new MyTaskParams(foo, bar, arple);
MyTask myTask = new MyTask();
myTask.execute(params);

另一种方法: 只需在 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
}

那就打电话

new MyTask(int foo, long bar, double arple).execute();

第二种方式就像大卫 · 瓦瑟的答案。

我喜欢 malajisi 的方法,但是如果你不喜欢,你不能使用 Bundle 类吗?

 Bundle myBundle = new Bundle();
myBundle.putInt("foo", foo);
myBundle.putLong("bar", bar);
myBundle.putDouble("arple", arple);

然后传递这个包并在 MyTask 中解压缩它。这是个糟糕的主意吗?您可以避免创建自定义类,并且如果您决定以后需要传递其他参数,那么它是灵活的。

更新: 我写这个答案已经有好几年了,我现在真的很不喜欢它。我建议不要使用 Bundle。如果您需要将多个参数传递到一个异步任务(或任何事情,真的) ,那么使用一个自定义类,该类可以同时保存所有参数。使用 bundle 是解决本不应该出现的问题的一个很好的解决方案。没有法律禁止创建一个自定义类来保存您确切需要的内容,也没有其他规定。

另外,为什么不使用协同程序? 异步任务是 所以2014。

这是通过子类化来解决的。 在官方的 Android AsyncTask 文档中,Google 有一个解决这个问题的例子(子类化) :

Http://developer.android.com/reference/android/os/asynctask.html

例如:

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");
}
}

The built in execute method accepts an array of 帕拉姆斯, but they all must be of the defined type.. so if you simply set the PARAM type to 反对, then you can pass in whatever you like as long as they are children of objects....

private class MyTask extends AsyncTask<Object, Void, Void> {

然后,在 doInBackGround 中,您只需将每个参数按照需要的顺序进行强制转换:

 @Override
protected void doInBackground(Object... params) {
Context t = (Context)params[0];
String a = (String) params[1];
List<LatLng> list = (List<LatLng>)params[2];
.
.
.

你的执行很简单:

 new MyTask().execute(context,somestring,list_of_points);

不如将它包装在您自己的包装器类中,或者包中,或者散列中,因为顺序依赖于双方,但是它会工作。当然,您可以将数组设置为 HashMap (,)的一个参数,并且基本上在这一点上自定义实现了一个 bundle,但是它将工作。