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


82

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

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


Answers:


153

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

这也可以。但我相信上述选择更为简单。
robguinness,2012年

10
实际上,这让我印象深刻。我一直在使用Object ... params的方式来执行此操作,由于某种原因,这样做感觉并不好或不安全。
Mafro34,2013年

1
像魅力伙伴一样工作。感谢分享。
Deepak S. Gavkar,

2
非常优雅,喜欢它。
Sipty

1
@DavidWasser:thanx用于您的更新,除了给定的解决方案效果很好!
Moussa

93

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

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


9
实际上,这是我最喜欢的三种传递不同类型参数的方式。没有要投射的对象,也无需创建其他类。
QuickFix 2014年

3
您需要在重写的构造函数中调用super()!
zyamys 2015年

2
@zyamys为什么在这里需要super()?据我了解,它将被自动调用。看到这里stackoverflow.com/a/2054040/984263
卡瑟斯

在这个线程的选项中,我最喜欢这个。没有帮助程序类,此类可以单独使用并描述其自己的要求。没有神秘的对象被传递。谢谢。
Vinnyq12年

这有效。感觉很脏,但是我懒得尝试其他任何东西。不敢相信没有一个很好的本地方法可以本地执行此操作。以后可能会在Java中提供支持<(String,Object,int),Void,Void>
Sirens

82

(严格来说)不可能将多个原语传递给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];

    }
    ...
}

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


您也可以将以下内容用于方法 protected LocationItemizedOverlay doInBackground(Object[] objects) ,并将以下内容添加至异步任务定义。 private class MyTask extends AsyncTask<Object, Void, Void>
汉尼·萨克

8

内置的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);

不如将其包装在您自己的包装器类,bundle,hash之类的形式中那样好,因为您的订单依赖于双方,但是它可以工作。当然,您可以只将数组作为HashMap(,)的参数,并且基本上可以自定义实现捆绑包,但是它将起作用。


1
这里的人们非常酷,拥有许多很棒的技术,这是我的最爱!
乔治·乌德森

7

我喜欢malajisi的方法,但如果不这样做,就不能使用Bundle类吗?

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

然后只需传递捆绑包并将其解包到MyTask中即可。这是一个可怕的主意吗?您避免创建自定义类,并且如果您决定以后需要传递其他参数,则该方法很灵活。

更新:我写了这个答案已经好几年了,现在我真的不喜欢它。我建议不要使用Bundle。如果您需要将多个参数传递到asynctask(或其他任何东西)中,请使用可同时保存所有参数的自定义类。使用捆绑软件可以很好地解决您不应该遇到的问题。没有法律禁止创建一个自定义类来完全容纳您所需要的东西,仅此而已。

另外,为什么不使用协程呢?异步任务是如此2014。


我认为这很不错
BQuadra

很好的主意。但是,我认为这不支持将自定义对象传递给doInBackground()
John Ward

1

这可以通过子类化解决。Google在官方的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");
    }
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.