How can you pass multiple primitive parameters to AsyncTask?

后端 未结 6 657
情歌与酒
情歌与酒 2020-11-27 10:36

There are related questions, such as How can I pass in 2 parameters to a AsyncTask class? , but I ran into the difficulty of trying in vain to pass multiple primitives as pa

相关标签:
6条回答
  • 2020-11-27 10:41

    Just wrap your primitives in a simple container and pass that as a parameter to AsyncTask, like this:

    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;
            ...
        }
    }
    

    Call it like this:

    MyTaskParams params = new MyTaskParams(foo, bar, arple);
    MyTask myTask = new MyTask();
    myTask.execute(params);
    
    0 讨论(0)
  • 2020-11-27 10:46

    This is solved via subclassing. Google has an example for solving this problem (subclassing) in the official Android AsyncTask Documentation:

    http://developer.android.com/reference/android/os/AsyncTask.html

    Example:

    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");
        }
    }
    
    0 讨论(0)
  • 2020-11-27 10:57

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

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

    Then in your doInBackGround, you simply cast each param in order back to what you need it to be:

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

    And your execute is simply:

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

    Not as good form as wrapping it in your own wrapper class, or a bundle, or hash or something, because you are order dependent on both sides, but it will work. Of course you could just make your array a param of HashMap(,) and you basically are custom implementing a bundle at that point, but it will work.

    0 讨论(0)
  • 2020-11-27 10:58

    Another way: You just need add MyTask constructor in your MyTask class:

    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
    }
    

    Then call

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

    A second way like David Wasser's Answer.

    0 讨论(0)
  • 2020-11-27 11:02

    I like malajisi's method, but if you didn't, couldn't you use the Bundle class?

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

    Then just pass the bundle and unpack it inside MyTask. Is this a terrible idea? You avoid creating a custom class, and it's flexible if you decide you need to pass additional parameters later.

    Update: It has been quite a few years since I wrote this answer, and I really dislike it now. I would recommend against using a Bundle. If you need to pass multiple parameters into an asynctask (or anything, really), use a custom class that holds all your parameters at once. Using a bundle is a fine solution to a problem you shouldn't have. There is no law against creating a custom class to hold exactly what you need, and nothing else.

    Also, why aren't you using coroutines? Asynctasks are so 2014.

    0 讨论(0)
  • 2020-11-27 11:04

    It is (strictly-speaking) NOT possible to pass multiple primitives to AsyncTask. For example, if you want to perform myTask.execute(long1, long2) and try to set up private class myTask extends AsyncTask<long, Void, Void> with the corresponding method:

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

    your IDE will likely complain about needing to override a supertype method. Note that you are using the so-called Varargs method signature for doInBackground, where (long... params) is like saying "I accept a variable number of longs, stored as an array called params. I don't completely understand what causes a compiler/IDE complaint to be raised, but I think it has to do with how the generic class Params is defined.

    In any case, it is possible to achieve what you want with no problem, provided you correctly cast your primitives to their respective non-primitive wrappers (e.g. int => Integer, long => Long, etc.). Actually, you don't need to explicitly cast your primitives to non-primitives. Java seems to handle that for you. You just need to set up your ASyncTask as follows (for the example of 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]
        }
        ...
    }
    

    You can then use this class as you originally intended, e.g.:

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

    Or for any number of primitives that you would like, PROVIDED THEY ARE OF THE SAME TYPE. If you need to pass multiple types of primitives, this can also be done, but you will need to modify the above to:

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

    This is more flexible, but it requires explicitly casting the parameters to their respective types. If this flexibility is not needed (i.e. a single data type), I recommend sticking to the first option, as it's slightly more readable.

    0 讨论(0)
提交回复
热议问题