【问题标题】:How can you pass multiple primitive parameters to AsyncTask?如何将多个原始参数传递给 AsyncTask?
【发布时间】:2012-08-17 16:08:40
【问题描述】:

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

问题是这样的:我有多个 primitive 参数(例如两个 long),我想将它们传递给 AsyncTask 以在后台执行 - 怎么做? (我的答案……在为此苦苦挣扎了一段时间后……可以在下面找到。)

【问题讨论】:

    标签: android android-asynctask primitive variadic-functions


    【解决方案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);
    

    【讨论】:

    • 这也有效。但我相信上述选项更简单。
    • 这让我觉得实际上好多了。我一直在使用 Object... params 的方式来做这件事,出于某种原因,这样做感觉不好或不安全。
    • 像魅力伙伴一样工作..感谢分享..!
    • 非常优雅,喜欢它。
    • @DavidWasser : 感谢您的更新,除了给定的解决方案效果很好!
    【解决方案2】:

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

    【讨论】:

    • 实际上这是我最喜欢的三种传递不同类型参数的方式。没有要转换的对象,也不需要创建额外的类。
    • 您需要在重写的构造函数中调用 super()!
    • @zyamys 为什么这里需要 super()?据我了解,它将被自动调用。见这里stackoverflow.com/a/2054040/984263
    • 在这个线程的选项中,我最喜欢这个。没有辅助类,这个类可以单独使用并描述自己的需求。没有神秘物体被传递。谢谢。
    • 这行得通。感觉很脏,但我懒得尝试其他任何东西。无法相信没有一种很好的本地方式可以在本地执行此操作。以后可能会支持 Java &lt;(String,Object,int),Void,Void&gt;
    【解决方案3】:

    (严格来说)不可能将多个原语传递给 AsyncTask。比如你想执行myTask.execute(long1, long2),尝试用对应的方法设置private class myTask extends AsyncTask&lt;long, Void, Void&gt;

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

    您的 IDE 可能会抱怨需要覆盖超类型方法。请注意,您正在为doInBackground 使用所谓的Varargs 方法签名,其中(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];
    
        }
        ...
    }
    

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

    【讨论】:

    • 您还可以将以下内容用于方法protected LocationItemizedOverlay doInBackground(Object[] objects),并为异步任务定义添加以下内容。 private class MyTask extends AsyncTask&lt;Object, Void, Void&gt;
    【解决方案4】:

    内置的 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(,) 的参数,然后你基本上是自定义实现一个包,但它会起作用。

    【讨论】:

    • 这里的人很酷,有很多很酷的技术,这是我的最爱!
    【解决方案5】:

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

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

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

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

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

    【讨论】:

    • 好主意。但是,我假设这不支持将自定义对象传递给 doInBackground()
    【解决方案6】:

    这是通过子类化解决的。 谷歌在官方的 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-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-03-05
      • 1970-01-01
      • 2014-07-29
      • 2020-11-07
      相关资源
      最近更新 更多