84

有相关的问题,例如如何将 2 个参数传递给 AsyncTask 类?,但我遇到了徒劳地尝试将多个原语作为参数传递给 AsyncTask 的困难,所以我想分享我的发现。现有的问题和答案中没有捕捉到这种微妙之处,因此我想帮助遇到与我相同的问题的任何人,并为他们减轻痛苦。

问题是这样的:我有多个原始参数(例如两个长整数),我想将它们传递给 AsyncTask 以在后台执行——如何完成?(我的答案......在挣扎了一段时间后......可以在下面找到。)

4

6 回答 6

157

只需将您的原语包装在一个简单的容器中并将其作为参数传递给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);
于 2012-08-22T09:23:57.073 回答
97

另一种方式:您只需要在 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();

第二种方式,例如 David Wasser 的回答。

于 2014-01-14T17:38:35.423 回答
83

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

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

您的 IDE 可能会抱怨需要覆盖超类型方法。请注意,您正在使用所谓的Varargs方法签名doInBackground,这(long... params)就像说“我接受可变数量的 long,存储为名为 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];

    }
    ...
}

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

于 2012-08-22T09:04:08.797 回答
9

内置的 execute 方法接受一个Params数组,但它们都必须是定义的类型。所以如果你只是将PARAM类型设置为OBJECT,那么只要它们是对象的子对象,你就可以传入任何你喜欢的东西。 ...

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(,) 的参数,并且你基本上是在那个时候自定义实现一个包,但它会起作用。

于 2018-01-28T03:25:10.197 回答
7

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

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

然后只需传递捆绑包并将其解压缩到 MyTask 中。这是一个可怕的想法吗?您避免创建自定义类,如果您决定稍后需要传递其他参数,它会很灵活。

更新:我写这个答案已经好几年了,我现在真的不喜欢它。我建议不要使用捆绑包。如果您需要将多个参数传递给异步任务(或任何东西,真的),请使用一个自定义类来一次保存所有参数。使用捆绑包可以很好地解决您不应该遇到的问题。没有法律禁止创建自定义类来准确保存您需要的内容,仅此而已。

另外,你为什么不使用协程?Asynctasks 在 2014 年是如此

于 2014-01-30T01:48:59.400 回答
1

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

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");
    }
}
于 2015-10-01T13:29:42.393 回答