code: public void start(@Nullable final DownloadListener listener, boolean isSerial) {
          final long startTime = SystemClock.uptimeMillis();
          Util.d(TAG, "start " + isSerial);
          started = true;
          final DownloadListener targetListener;
          if (contextListener != null) {
              targetListener = new DownloadListenerBunch.Builder()
                      .append(listener)
                      .append(new QueueAttachListener(this, contextListener, tasks.length))
                      .build();
          } else {
              targetListener = listener;
          }
  
          if (isSerial) {
              final List<DownloadTask> scheduleTaskList = new ArrayList<>();
              Collections.addAll(scheduleTaskList, tasks);
              Collections.sort(scheduleTaskList);
              executeOnSerialExecutor(new Runnable() {
                  @Override public void run() {
                      for (DownloadTask task : scheduleTaskList) {
                          if (!isStarted()) {
                              callbackQueueEndOnSerialLoop(task.isAutoCallbackToUIThread());
                              break;
                          }
                          task.execute(targetListener);
                      }
                  }
              });
          } else {
              DownloadTask.enqueue(tasks, targetListener);
          }
          Util.d(TAG,
                  "start finish " + isSerial + " " + (SystemClock.uptimeMillis() - startTime) + "ms");
      }
docs: Start queue.
  
  @param listener the listener for each task, if you have already provided
  {@link #contextListener}, it's accept {@code null} for each task's listener.
  @param isSerial whether download queue serial or parallel.