@Override
  public void run() {

    HttpURLConnection conn = null;
    InputStream inputStream = null;

    DetectUrlFileFailReason failReason = null;

    try {
      // check URL
      if (!UrlUtil.isUrl(mUrl)) {
        // error url illegal
        failReason =
            new DetectUrlFileFailReason("url illegal!", DetectUrlFileFailReason.TYPE_URL_ILLEGAL);
      }
      // URL legal
      else {
        DownloadFileInfo downloadFileInfo = mDownloadFileCacher.getDownloadFile(mUrl);
        if (downloadFileInfo != null) {
          // 1.in the download file database,notify
          if (mOnDetectUrlFileListener != null) {
            OnDetectUrlFileListener.MainThreadHelper.onDetectUrlFileExist(
                mUrl, mOnDetectUrlFileListener);
          }
          return;
        }

        conn = HttpConnectionHelper.createDetectConnection(mUrl, CONNECT_TIMEOUT, CHARSET);

        int redirectCount = 0;
        while (conn.getResponseCode() / 100 == 3 && redirectCount < MAX_REDIRECT_COUNT) {
          conn = HttpConnectionHelper.createDetectConnection(mUrl, CONNECT_TIMEOUT, CHARSET);
          redirectCount++;
        }

        Log.d(
            TAG,
            "DetectUrlFileTask.run 探测文件,重定向:"
                + redirectCount
                + "次"
                + ",最大重定向次数:"
                + MAX_REDIRECT_COUNT
                + ",url:"
                + mUrl);

        if (redirectCount > MAX_REDIRECT_COUNT) {
          // error over max redirect
          failReason =
              new DetectUrlFileFailReason(
                  "over max redirect:" + MAX_REDIRECT_COUNT + "!",
                  DetectUrlFileFailReason.TYPE_URL_OVER_REDIRECT_COUNT);
        } else {
          switch (conn.getResponseCode()) {
              // http ok
            case HttpURLConnection.HTTP_OK:
              // get file name
              String fileName = mUrl.substring(mUrl.lastIndexOf('/') + 1);
              // get file size
              int fileSize = conn.getContentLength();
              // get etag
              String eTag = conn.getHeaderField("ETag");
              // get acceptRangeType,bytes usually if supported range transmission
              String acceptRangeType = conn.getHeaderField("Accept-Ranges");

              DetectUrlFileInfo detectUrlFileInfo =
                  new DetectUrlFileInfo(
                      mUrl, fileSize, eTag, acceptRangeType, mDownloadSaveDir, fileName);
              // add to memory cache
              mDetectUrlFileCacher.addOrUpdateDetectUrlFile(detectUrlFileInfo);

              // 2.need to create download file
              if (mOnDetectUrlFileListener != null) {
                OnDetectUrlFileListener.MainThreadHelper.onDetectNewDownloadFile(
                    mUrl, fileName, mDownloadSaveDir, fileSize, mOnDetectUrlFileListener);
              }
              break;
              // 404 not found
            case HttpURLConnection.HTTP_NOT_FOUND:
              // error url file does not exist
              failReason =
                  new DetectUrlFileFailReason(
                      "url file does not exist!", DetectUrlFileFailReason.TYPE_HTTP_FILE_NOT_EXIST);
              break;
              // other,ResponseCode error
            default:
              // error ResponseCode error
              failReason =
                  new DetectUrlFileFailReason(
                      "ResponseCode:" + conn.getResponseCode() + " " + "error,can not read data!",
                      DetectUrlFileFailReason.TYPE_BAD_HTTP_RESPONSE_CODE);
              break;
          }
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
      failReason = new DetectUrlFileFailReason(e);
    } finally {
      if (inputStream != null) {
        try {
          inputStream.close();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
      if (conn != null) {
        conn.disconnect();
      }
      // error occur
      if (failReason != null) {
        if (mOnDetectUrlFileListener != null) {
          OnDetectUrlFileListener.MainThreadHelper.onDetectUrlFileFailed(
              mUrl, failReason, mOnDetectUrlFileListener);
        }
      }
    }
  }
  @Override
  public void run() {

    try {
      mDownloadFilesNeedDelete.clear();
      mDownloadFilesDeleted.clear();
      mDownloadFilesSkip.clear();

      for (String url : mUrls) {
        if (!UrlUtil.isUrl(url)) {
          continue;
        }
        DownloadFileInfo downloadFileInfo = getDownloadFile(url);
        if (downloadFileInfo != null) {
          //                    synchronized (mLock) {//lock
          mDownloadFilesNeedDelete.add(downloadFileInfo);
          //                    }
        }
      }

      // prepare to delete
      notifyDeleteDownloadFilesPrepared();

      // delete every single download file listener
      final OnDeleteDownloadFileListener onDeleteEverySingleDownloadFileListener =
          new OnDeleteSingleDownloadFileListener();

      // delete every single one
      for (int i = 0; i < mDownloadFilesNeedDelete.size(); i++) {

        DownloadFileInfo downloadFileInfo = mDownloadFilesNeedDelete.get(i);
        if (downloadFileInfo == null) {
          // skip one
          synchronized (mLock) { // lock
            mDownloadFilesSkip.add(downloadFileInfo);
          }
          continue;
        }

        final String finalUrl = downloadFileInfo.getUrl();

        // if the task stopped,notify completed
        if (isStopped()) {

          Log.d(TAG, TAG + ".run 批量删除任务被取消,无法继续删除,任务即将结束");

          // goto finally, notifyDeleteDownloadFilesCompleted()
          return;
        }

        // downloading
        if (mDownloadTaskPauseable.isDownloading(finalUrl)) {

          Log.d(TAG, TAG + ".run 需要先暂停单个下载任务后删除,url:" + finalUrl);

          // pause first
          mDownloadTaskPauseable.pause(
              finalUrl,
              new OnStopFileDownloadTaskListener() {
                @Override
                public void onStopFileDownloadTaskSucceed(String url) {

                  Log.d(TAG, TAG + ".run 暂停单个下载任务成功,开始删除,url:" + finalUrl);

                  // if the task stopped,notify completed
                  if (isStopped()) {

                    Log.d(TAG, TAG + ".run 批量删除任务被取消,无法继续删除,任务即将结束");

                    // notify caller
                    notifyDeleteDownloadFilesCompleted();
                    return;
                  }

                  // stopped, continue delete
                  runSingleDeleteTask(finalUrl, onDeleteEverySingleDownloadFileListener, false);
                }

                @Override
                public void onStopFileDownloadTaskFailed(
                    String url, StopDownloadFileTaskFailReason failReason) {

                  // if the task stopped, notify completed
                  if (isStopped()) {

                    Log.d(TAG, TAG + ".run 批量删除任务被取消,无法继续删除,任务即将结束");

                    // notify caller
                    notifyDeleteDownloadFilesCompleted();
                    return;
                  }

                  if (failReason != null) {
                    if (StopDownloadFileTaskFailReason.TYPE_TASK_HAS_BEEN_STOPPED.equals(
                        failReason.getType())) {
                      // stopped, continue delete
                      runSingleDeleteTask(finalUrl, onDeleteEverySingleDownloadFileListener, false);
                      return;
                    }
                  }

                  Log.d(TAG, TAG + ".run 暂停单个下载任务失败,无法删除,url:" + finalUrl);

                  // failed
                  synchronized (mLock) { // lock
                    mDownloadFilesSkip.add(getDownloadFile(finalUrl));
                  }
                }
              });
        } else {
          // run delete task directly
          runSingleDeleteTask(finalUrl, onDeleteEverySingleDownloadFileListener, true);
        }
      }
    } catch (Exception e) {
      e.printStackTrace();
      // error, ignore
    } finally {

      if (isStopped()) {
        // notify caller
        notifyDeleteDownloadFilesCompleted();
      }

      Log.d(TAG, TAG + ".run 批量删除文件主任务【已结束】,但是通过暂停下载中的文件删除任务可能还没有结束");
    }
  }