/**
   * Start the download queue by the same listener
   *
   * @param listener start download by same listener
   * @param isSerial is execute them linearly
   */
  public void start(final FileDownloadListener listener, final boolean isSerial) {

    if (listener == null) {
      return;
    }

    final List<BaseDownloadTask> list = FileDownloadList.getImpl().copy(listener);

    if (FileDownloadMonitor.isValid()) {
      FileDownloadMonitor.getMonitor().onRequestStart(list.size(), isSerial, listener);
    }

    if (FileDownloadLog.NEED_LOG) {
      FileDownloadLog.v(
          this, "start list size[%d] listener[%s] isSerial[%B]", list.size(), listener, isSerial);
    }

    if (isSerial) {
      // serial
      final Handler serialHandler = createSerialHandler(list);
      Message msg = serialHandler.obtainMessage();
      msg.what = WHAT_SERIAL_NEXT;
      msg.arg1 = 0;
      serialHandler.sendMessage(msg);
    } else {
      // parallel
      for (final BaseDownloadTask downloadTask : list) {
        downloadTask.start();
      }
    }
  }
  private int startUnchecked() {
    if (FileDownloadMonitor.isValid()) {
      FileDownloadMonitor.getMonitor().onRequestStart(this);
    }

    if (FileDownloadLog.NEED_LOG) {
      FileDownloadLog.v(
          this,
          "call start " + "url[%s], setPath[%s] listener[%s], tag[%s]",
          url,
          path,
          listener,
          tag);
    }

    boolean ready = true;

    try {
      _adjust();
      _checkFile(path);
    } catch (Throwable e) {
      ready = false;

      FileDownloadList.getImpl().add(this);
      FileDownloadList.getImpl().remove(this, catchException(e));
    }

    if (ready) {
      FileDownloadTaskLauncher.getImpl().launch(this);
    }

    return getId();
  }
  /**
   * start download
   *
   * <p>用于启动一个单独任务
   *
   * @return Download id
   */
  public int start() {
    if (FileDownloadMonitor.isValid()) {
      FileDownloadMonitor.getMonitor().onRequestStart(this);
    }

    if (FileDownloadLog.NEED_LOG) {
      FileDownloadLog.v(
          this,
          "call start " + "url[%s], setPath[%s] listener[%s], tag[%s]",
          url,
          path,
          listener,
          tag);
    }

    boolean ready = true;

    try {
      _adjust();
      _checkFile(path);
    } catch (Throwable e) {
      ready = false;

      setStatus(FileDownloadStatus.error);
      setEx(e);
      FileDownloadList.getImpl().add(this);
      FileDownloadList.getImpl().removeByError(this);
    }

    if (ready) {
      FileDownloadEventPool.getImpl().send2Service(new DownloadTaskEvent(this).requestStart());
    }

    return getDownloadId();
  }
  // ------------------
  // Begin task execute
  void begin() {
    if (FileDownloadMonitor.isValid()) {
      FileDownloadMonitor.getMonitor().onTaskBegin(this);
    }

    if (FileDownloadLog.NEED_LOG) {
      FileDownloadLog.v(this, "filedownloader:lifecycle:start %s by %d ", toString(), getStatus());
    }
  }
  // End task
  void over() {
    if (FileDownloadMonitor.isValid()) {
      FileDownloadMonitor.getMonitor().onTaskOver(this);
    }

    if (FileDownloadLog.NEED_LOG) {
      FileDownloadLog.v(this, "filedownloader:lifecycle:over %s by %d ", toString(), getStatus());
    }

    if (finishListenerList != null) {
      final ArrayList<FinishListener> listenersCopy =
          (ArrayList<FinishListener>) finishListenerList.clone();
      final int numListeners = listenersCopy.size();
      for (int i = 0; i < numListeners; ++i) {
        listenersCopy.get(i).over();
      }
    }
  }