15

What are the reasons that Google use varargs for the parameters in the AsyncTask? For example the methods execute(), doInBackground() and publishProgress() all use the [Type]... notation.

I think that makes it "harder" to use so they must have some good reasons which I overlooked?


So, either we have no parameters, one or many parameters. Let's break it down:

  1. No parameters (easy): Params parameter is Void and that's it. (The methods cannot use it... so that's pretty safe.)

  2. One parameter: Here, I at least, feel the need to make a check at the beginning of the doInBackground() method. For example, here is a task receiving an Integer and producing a result of type Double:

    public Double doInBackground(Integer... myParameters) {
        // we are only expecting one parameter
        if (myParameters.length != 1)
            throw new IllegalArgumentException("!= 1");
    
        return 100d * myParameters[0];
    }
    
  3. More than one parameter. Now here must be where Google made the right choice? But as I see it's either you are interested in a list of parameters of the same type, or you want different types of parameters. Google only addressed one of these cases (with different types you need some kind of common interface. In many cases I end up with Object... and that isn't really type safe...)


So, what is the problem if we just remove the varargs altogether? Here's a subset of the methods:

class AsyncTask<Param, Progress, Result> {

    abstract Result doInBackground(Param param);
    void publishProgress(Progress progress) { ... }
}

This would work for all the cases above. For example, if we want to handle an array of parameters we could just use an array type param:

class MyAsyncTask extends AsyncTask<String[], Integer, String> { 

    String doInBackground(String[] param) {
        return Arrays.toString(param);
    }
}

I don't see when it could be of any practical use. But I'm sure I'm missing something curia that I need to know about. :)

dacwe
  • 43,066
  • 12
  • 116
  • 140
  • possible duplicate of [When do you use varargs in Java?](http://stackoverflow.com/questions/766559/when-do-you-use-varargs-in-java) – CommonsWare Mar 06 '13 at 00:09
  • 1
    Why is this question a duplicate of that question? It is a specific interface I'm questioning. Why did the developers use varargs this specific problem. I thought I made it clear that I know what it is and I do use it when appropriate.. :) – dacwe Mar 06 '13 at 00:10
  • "It is a specific interface I'm questioning" -- there is nothing in your arguments that has anything specific to do with `AsyncTask`. You could be complaining about the use of varargs with a `Restaurant` class. If your question were focused on the impacts of varargs on, say, how `AsyncTask` handles communication between threads, then it might not be a duplicate. But, as it stands, IMHO, the answers presented in the question I cited would seem to cover this question as well. – CommonsWare Mar 06 '13 at 00:14
  • Furthermore, "the reasons that Google use varargs for the parameters" is impossible to answer, unless we can convince Romain Guy (original author of `AsyncTask`) to chime in on this question. The closest thing to an answer for why varargs in this case is the answers to why you would use varargs in general, which is covered in the linked-to question. – CommonsWare Mar 06 '13 at 00:19
  • I have lit up the Guy-Signal, to see if I can get you a definitive answer. But if he writes back that "it seemed like a good idea at the time", don't say I didn't warn you... :-) – CommonsWare Mar 06 '13 at 00:40
  • :-) Haha! That settles it! I will just use it from now on. But I'm a bit sad that it wasn't something I didn't know about. Thanks again! – dacwe Mar 06 '13 at 00:48
  • 10
    https://twitter.com/romainguy/status/309102518569410560 – a.bertucci Mar 06 '13 at 01:01
  • On the off-chance the aforementioned Twitter link rots, Romain Guy tweeted, “It’s convenient and easy way to process several tasks (to decode several images in the background for instance.)” – Steve Pomeroy Aug 26 '14 at 22:27

2 Answers2

2

I think the vararg arguments just makes it a bit more convenient when you call to execute the AsyncTask.

As long as we are wondering why AsyncTask was designed the way it is: :-)

In my opinion, the Param and Result templates would not have been really necessary to accomplish the same.

When you write your own AsyncTask, you subclass it. Instead of declaring the actual types for Param and Result, you may as well add final fields to your subclass (Params) and add modifiable fields to your subclass (Result). E.g:

public class MyAsyncTask extends AsyncTask<Void> {
    // Input Params
    private final int inParam1;
    private final String inParam2;

    // Output Results
    private Bitmap resultBitmap;

    public MyAsyncTask(int param1, String param2) {
        inParam1 = param1;
        inParam2 = param2;
    }

    @Override
    protected void doInBackground() {
        // use param1 and param2 as input to the background process.
        ...
        ...
        // Finished: assign to result
        resultBitmap = ....;
    } 

    @Override
    protected void onPostExecute() {
        // Send result to UI.
        ... resultBitmap ...
        ...
        resultBitmap = null;
    }
}

No generics needed, maybe except for showing Progress.

This is what i usually do anyway, especially if the result is a Bitmap. The value returned by doInBackground and handled by onPostExecute is not set to null after all is set and done and it sneakily 'leaks' Bitmaps this way (memory errors caused by bitmaps held in memory by completed/finished AsyncTasks).

Streets Of Boston
  • 12,576
  • 2
  • 25
  • 28
1

I think you are right, the only usage of the type parameter Params is in Params..., which implies that it is really the Params[] that is wanted here. However now the API only works with array types, it misses a whole lot of non-array types.

The only advantage of varargs is at the call site, but it's not much either -

Google's version:

AsyncTask<String> task = ...
task.execute("a", "b");

Your version:

AsyncTask<List<String>> task = ...
task.execute(Arrays.asList("a", "b"));
irreputable
  • 44,725
  • 9
  • 65
  • 93