如何将多个原始参数传递给AsyncTask?

时间:2012-08-22 09:04:09

标签: android android-asynctask primitive variadic-functions

有一些相关的问题,例如How can I pass in 2 parameters to a AsyncTask class? ,但是我遇到了将多个原语作为参数传递给AsyncTask而徒劳无功的困难,因此我想分享我发现的内容。在现有的问题和答案中没有捕捉到这种微妙之处,所以我想帮助那些遇到与我一样的问题的人,并为他们节省痛苦。

问题是:我有多个原始参数(例如两个long),我想传递给AsyncTask以在后台执行 - 它怎么能完成? (我的回答......经过一段时间的挣扎......可以在下面找到。)

6 个答案:

答案 0 :(得分:146)

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

答案 1 :(得分:87)

另一种方法:您只需要在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的回答。

答案 2 :(得分:76)

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

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

您的IDE可能会抱怨需要覆盖超类型方法。请注意,您正在使用doInBackground的所谓Varargs方法签名,其中(long... params)就像是在说“我接受一个可变数量的long,存储为一个名为params的数组。我不知道完全理解导致编译器/ IDE投诉的原因,但我认为它与如何定义泛型类Params有关。

在任何情况下,只要您正确地将基元转换为各自的非基本包装器(例如int =&gt; Integer,long =&gt; Long等),就可以毫无问题地实现您想要的效果。实际上,您不需要将基元显式转换为非基元。 Java似乎为你处理这个问题。您只需按如下方式设置ASyncTask(例如longs):

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

    }
    ...
}

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

答案 3 :(得分:6)

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

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

然后只需传递捆绑包并将其解压缩到MyTask中。这是一个糟糕的主意吗?您可以避免创建自定义类,如果您决定稍后需要传递其他参数,则可以灵活使用。

答案 4 :(得分:5)

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

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

然后在你的doInBackGround中,你只需按顺序投射每个参数就可以了:

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

你的执行就是:

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

不如将它包装在您自己的包装器类,包或哈希或其他东西中那样好,因为您的订单依赖于双方,但它会起作用。当然你可以让你的数组成为HashMap(,)的一个参数,你基本上是在那时自定义实现一个包,但它会起作用。

答案 5 :(得分: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");
    }
}