コード例 #1
0
    private void goNext(final int nextIndex) {
      if (this.handler == null || this.list == null) {
        FileDownloadLog.w(
            this,
            "need go next %d, but params is not ready %s %s",
            nextIndex,
            this.handler,
            this.list);
        return;
      }

      Message nextMsg = this.handler.obtainMessage();
      nextMsg.what = WHAT_SERIAL_NEXT;
      nextMsg.arg1 = nextIndex;
      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(
            SerialHandlerCallback.class,
            "start next %s %s",
            this.list == null
                ? null
                : this.list.get(0) == null ? null : this.list.get(0).getListener(),
            nextMsg.arg1);
      }
      this.handler.sendMessage(nextMsg);
    }
コード例 #2
0
  public static boolean isBreakpointAvailable(
      final int id, final FileDownloadModel model, final String path) {
    boolean result = false;

    do {
      if (path == null) {
        if (FileDownloadLog.NEED_LOG) {
          FileDownloadLog.d(FileDownloadMgr.class, "can't continue %d path = null", id);
        }
        break;
      }

      File file = new File(path);
      final boolean isExists = file.exists();
      final boolean isDirectory = file.isDirectory();

      if (!isExists || isDirectory) {
        if (FileDownloadLog.NEED_LOG) {
          FileDownloadLog.d(
              FileDownloadMgr.class,
              "can't continue %d file not suit, exists[%B], directory[%B]",
              id,
              isExists,
              isDirectory);
        }
        break;
      }

      final long fileLength = file.length();

      if (model.getSoFar() == 0) {
        if (FileDownloadLog.NEED_LOG) {
          FileDownloadLog.d(
              FileDownloadMgr.class, "can't continue %d the downloaded-record is zero.", id);
        }
        break;
      }

      if (fileLength < model.getSoFar()
          || (model.getTotal() != -1 // not chunk transfer encoding data
              && (fileLength > model.getTotal() || model.getSoFar() >= model.getTotal()))) {
        // dirty data.
        if (FileDownloadLog.NEED_LOG) {
          FileDownloadLog.d(
              FileDownloadMgr.class,
              "can't continue %d dirty data" + " fileLength[%d] sofar[%d] total[%d]",
              id,
              fileLength,
              model.getSoFar(),
              model.getTotal());
        }
        break;
      }

      result = true;
    } while (false);

    return result;
  }
コード例 #3
0
    @Override
    public boolean handleMessage(final Message msg) {
      if (msg.what == WHAT_SERIAL_NEXT) {
        if (msg.arg1 >= list.size()) {
          // final serial tasks
          if (this.handler != null && this.handler.getLooper() != null) {
            this.handler.getLooper().quit();
            this.handler = null;
            this.list = null;
          }

          if (FileDownloadLog.NEED_LOG) {
            FileDownloadLog.d(
                SerialHandlerCallback.class,
                "final serial %s %d",
                this.list == null
                    ? null
                    : this.list.get(0) == null ? null : this.list.get(0).getListener(),
                msg.arg1);
          }
          return true;
        }

        final BaseDownloadTask task = this.list.get(msg.arg1);
        synchronized (pauseLock) {
          if (!FileDownloadList.getImpl().contains(task)) {
            // pause?
            if (FileDownloadLog.NEED_LOG) {
              FileDownloadLog.d(
                  SerialHandlerCallback.class,
                  "direct go next by not contains %s %d",
                  task,
                  msg.arg1);
            }
            goNext(msg.arg1 + 1);
            return true;
          }
        }

        list.get(msg.arg1)
            .addFinishListener(
                new BaseDownloadTask.FinishListener() {
                  private int index;

                  public BaseDownloadTask.FinishListener setIndex(int index) {
                    this.index = index;
                    return this;
                  }

                  @Override
                  public void over() {
                    goNext(this.index);
                  }
                }.setIndex(msg.arg1 + 1))
            .start();
      }
      return true;
    }
コード例 #4
0
  public boolean clearTaskData(int id) {
    if (id == 0) {
      FileDownloadLog.w(this, "The task[%d] id is invalid, can't clear it.", id);
      return false;
    }

    if (isDownloading(id)) {
      FileDownloadLog.w(this, "The task[%d] is downloading, can't clear it.", id);
      return false;
    }

    mHelper.remove(id);
    return true;
  }
コード例 #5
0
  /**
   * Reuse this task withhold request params: path、url、header、isForceReDownloader、etc.
   *
   * @return Successful reuse or not.
   */
  public boolean reuse() {
    if (isRunning()) {
      FileDownloadLog.w(
          this,
          "This task is running %d, if you want start the same task,"
              + " please create a new one by FileDownloader.create",
          getId());
      return false;
    }

    this.using = false;
    this.etag = null;
    this.resuming = false;
    this.retryingTimes = 0;
    this.isReusedOldFile = false;
    this.ex = null;
    resetSpeed();
    clearMarkAdded2List();

    setStatus(FileDownloadStatus.INVALID_STATUS);
    this.soFarBytes = 0;
    this.totalBytes = 0;
    messenger.reAppointment(this);

    return true;
  }
コード例 #6
0
 /** Sets the tag associated with this task, not be used by internal. */
 public BaseDownloadTask setTag(final Object tag) {
   this.tag = tag;
   if (FileDownloadLog.NEED_LOG) {
     FileDownloadLog.d(this, "setTag %s", tag);
   }
   return this;
 }
コード例 #7
0
 /** @param path Absolute path for save the download file */
 public BaseDownloadTask setPath(final String path) {
   this.path = path;
   if (FileDownloadLog.NEED_LOG) {
     FileDownloadLog.d(this, "setPath %s", path);
   }
   return this;
 }
コード例 #8
0
  public FileDownloadMgr() {

    final DownloadMgrInitialParams params = FileDownloadHelper.getDownloadMgrInitialParams();
    mHelper = new FileDownloadDBHelper();

    final OkHttpClient client;
    final int maxNetworkThreadCount;
    if (params != null) {
      client = params.makeCustomOkHttpClient();
      maxNetworkThreadCount = params.getMaxNetworkThreadCount();
    } else {
      client = null;
      maxNetworkThreadCount = 0;
    }

    if (FileDownloadLog.NEED_LOG) {
      FileDownloadLog.d(
          this,
          "init the download manager with initialParams: "
              + "okhttpClient[is customize: %B], maxNetworkThreadCount[%d]",
          client != null,
          maxNetworkThreadCount);
    }

    // init client
    if (this.client != client) {
      this.client = client;
    } else {
      // in this case, the client must be null, see #41
      this.client = new OkHttpClient();
    }

    mThreadPool = new FileDownloadThreadPool(maxNetworkThreadCount);
  }
コード例 #9
0
  private void _start() {

    try {

      // Whether service was already started.
      if (!_checkCanStart()) {
        // Not ready
        return;
      }

      FileDownloadList.getImpl().add(this);
      if (_checkCanReuse()) {
        // Will be removed when the complete message is received in #update
        return;
      }

      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(this, "start downloaded by ui process %s", getUrl());
      }

      if (!_startExecute()) {
        setEx(new RuntimeException("not run download, not got download id"));
        FileDownloadList.getImpl().removeByError(this);
      }

    } catch (Throwable e) {
      e.printStackTrace();

      setEx(e);
      FileDownloadList.getImpl().removeByError(this);
    }
  }
コード例 #10
0
  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();
  }
コード例 #11
0
  /**
   * Why pause? not stop? because invoke this method(pause) will clear all data about this task in
   * memory, and stop the total processing about this task. but when you start the paused task, it
   * would be continue downloading from the breakpoint as default.
   *
   * @return If true, successful pause this task by status of pause, otherwise this task has already
   *     in over status before invoke this method(Maybe occur high concurrent situation).
   * @see FileDownloader#pause(int)
   * @see FileDownloader#pause(FileDownloadListener)
   * @see FileDownloader#pauseAll()
   */
  public boolean pause() {
    if (FileDownloadStatus.isOver(getStatus())) {
      if (FileDownloadLog.NEED_LOG) {
        /**
         * The over-status call-backed and set the over-status to this task between here area and
         * remove from the {@link FileDownloadList}.
         *
         * <p>High concurrent cause.
         */
        FileDownloadLog.d(
            this,
            "High concurrent cause, Already is over, can't pause " + "again, %d %d",
            getStatus(),
            getId());
      }
      return false;
    }
    setStatus(FileDownloadStatus.paused);

    _pauseExecute();

    calcAverageSpeed(this.soFarBytes);
    // For make sure already added event listener for receive paused event
    FileDownloadList.getImpl().add(this);
    FileDownloadList.getImpl().remove(this, MessageSnapshotTaker.catchPause(this));

    return true;
  }
コード例 #12
0
  void _start() {

    try {
      // Whether service was already started.
      if (!_checkCanStart()) {
        this.using = false;
        // Not ready
        return;
      }

      FileDownloadList.getImpl().add(this);
      if (_checkCanReuse()) {
        // Will be removed when the complete message is received in #update
        return;
      }

      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(this, "start downloaded by ui process %s", getUrl());
      }

      _startExecute();

    } catch (Throwable e) {
      e.printStackTrace();

      FileDownloadList.getImpl().remove(this, catchException(e));
    }
  }
コード例 #13
0
  /**
   * 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();
  }
コード例 #14
0
  /**
   * 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();
      }
    }
  }
コード例 #15
0
 // Clear References
 void clear() {
   if (finishListenerList != null) {
     finishListenerList.clear();
   }
   if (FileDownloadLog.NEED_LOG) {
     FileDownloadLog.d(this, "clear %s", this);
   }
 }
コード例 #16
0
  /**
   * @param listener For callback download status(pending,connected,progress,
   *     blockComplete,retry,error,paused,completed,warn)
   */
  public BaseDownloadTask setListener(final FileDownloadListener listener) {
    this.listener = listener;

    if (FileDownloadLog.NEED_LOG) {
      FileDownloadLog.d(this, "setListener %s", listener);
    }
    return this;
  }
コード例 #17
0
 /**
  * Pause the download task by the downloadId
  *
  * @param downloadId pause download by download id
  * @see #pause(FileDownloadListener)
  */
 public void pause(final int downloadId) {
   BaseDownloadTask downloadTask = FileDownloadList.getImpl().get(downloadId);
   if (downloadTask == null) {
     FileDownloadLog.w(this, "request pause but not exist %d", downloadId);
     return;
   }
   downloadTask.pause();
 }
コード例 #18
0
 // Assign default value if need
 private void _adjust() {
   if (path == null) {
     path = FileDownloadUtils.getDefaultSaveFilePath(url);
     if (FileDownloadLog.NEED_LOG) {
       FileDownloadLog.d(this, "save path is null to %s", path);
     }
   }
 }
コード例 #19
0
  /** @return can resume by break point */
  public static boolean isBreakpointAvailable(final int id, final FileDownloadModel model) {
    if (model == null) {
      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(FileDownloadMgr.class, "can't continue %d model == null", id);
      }
      return false;
    }

    if (model.getTempFilePath() == null) {
      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(FileDownloadMgr.class, "can't continue %d temp path == null", id);
      }
      return false;
    }

    return isBreakpointAvailable(id, model, model.getTempFilePath());
  }
コード例 #20
0
  // ------------------
  // 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());
    }
  }
コード例 #21
0
  /**
   * Ready task( For queue task )
   *
   * <p>用于将几个task绑定为一个队列启动的结束符
   *
   * @return downloadId
   * @see FileDownloader#start(FileDownloadListener, boolean)
   */
  public int ready() {

    if (FileDownloadLog.NEED_LOG) {
      FileDownloadLog.d(this, "ready 2 download %s", toString());
    }

    FileDownloadList.getImpl().ready(this);

    return getId();
  }
コード例 #22
0
  /** Pause all running task */
  public void pauseAll() {
    List<Integer> list = mThreadPool.getAllExactRunningDownloadIds();

    if (FileDownloadLog.NEED_LOG) {
      FileDownloadLog.d(this, "pause all tasks %d", list.size());
    }

    for (Integer id : list) {
      pause(id);
    }
  }
コード例 #23
0
  boolean updateKeepFlow(final MessageSnapshot snapshot) {
    final int currentStatus = getStatus();
    final int nextStatus = snapshot.getStatus();

    if (FileDownloadStatus.paused == currentStatus && FileDownloadStatus.isIng(nextStatus)) {
      if (FileDownloadLog.NEED_LOG) {
        /**
         * Occur such situation, must be the running-status waiting for turning up in flow thread
         * pool(or binder thread) when there is someone invoked the {@link #pause()} .
         *
         * <p>High concurrent cause.
         */
        FileDownloadLog.d(
            this,
            "High concurrent cause, callback pending, but has already" + " be paused %d",
            getId());
      }
      return true;
    }

    if (!FileDownloadStatus.isKeepFlow(currentStatus, nextStatus)) {
      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(
            this,
            "can't update status change by keep flow, %d, but the" + " current status is %d, %d",
            status,
            getStatus(),
            getId());
      }

      return false;
    }

    update(snapshot);
    return true;
  }
コード例 #24
0
  boolean updateKeepAhead(final MessageSnapshot snapshot) {
    if (!FileDownloadStatus.isKeepAhead(getStatus(), snapshot.getStatus())) {
      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(
            this,
            "can't update status change by keep ahead, %d, but the" + " current status is %d, %d",
            status,
            getStatus(),
            getId());
      }
      return false;
    }

    update(snapshot);
    return true;
  }
コード例 #25
0
  /**
   * Pause task
   *
   * <p>停止任务, 对于线程而言会直接关闭,清理所有相关数据,不会hold住任何东西
   *
   * <p>如果重新启动,默认会断点续传,所以为pause
   */
  public boolean pause() {
    setStatus(FileDownloadStatus.paused);

    final boolean result = _pauseExecute();

    // For make sure already added event listener for receive paused event
    FileDownloadList.getImpl().add(this);
    if (result) {
      FileDownloadList.getImpl().removeByPaused(this);
    } else {
      FileDownloadLog.w(this, "paused false %s", toString());
      // 一直依赖不在下载进程队列中
      // 只有可能是 串行 还没有执行到 or 并行还没来得及加入进的
      FileDownloadList.getImpl().removeByPaused(this);
    }
    return result;
  }
コード例 #26
0
  // 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();
      }
    }
  }
コード例 #27
0
  @Override
  public boolean isDownloading(FileDownloadModel model) {
    if (model == null) {
      return false;
    }

    final boolean isInPool = mThreadPool.isInThreadPool(model.getId());
    boolean isDownloading;

    do {
      if (FileDownloadStatus.isOver(model.getStatus())) {

        //noinspection RedundantIfStatement
        if (isInPool) {
          // already finished, but still in the pool.
          // handle as downloading.
          isDownloading = true;
        } else {
          // already finished, and not in the pool.
          // make sense.
          isDownloading = false;
        }
      } else {
        if (isInPool) {
          // not finish, in the pool.
          // make sense.
          isDownloading = true;
        } else {
          // not finish, but not in the pool.
          // beyond expectation.
          FileDownloadLog.e(
              this,
              "%d status is[%s](not finish) & but not in the pool",
              model.getId(),
              model.getStatus());
          // handle as not in downloading, going to re-downloading.
          isDownloading = false;
        }
      }
    } while (false);

    return isDownloading;
  }
コード例 #28
0
  public boolean pause(final int id) {
    final FileDownloadModel model = mHelper.find(id);
    if (model == null) {
      return false;
    }

    if (FileDownloadLog.NEED_LOG) {
      FileDownloadLog.d(this, "paused %d", id);
    }

    mThreadPool.cancel(id);
    /**
     * 耦合 by {@link FileDownloadRunnable#run()} 中的 {@link
     * com.squareup.okhttp.Request.Builder#tag(Object)} 目前在okHttp里还是每个单独任务
     */
    // 之所以注释掉,不想这里回调error,okHttp中会根据okHttp所在被cancel的情况抛error
    //        client.cancel(id);
    return true;
  }
コード例 #29
0
  // synchronize for safe: check downloading, check resume, update data, execute runnable
  public synchronized void start(
      final String url,
      final String path,
      final boolean pathAsDirectory,
      final int callbackProgressTimes,
      final int callbackProgressMinIntervalMillis,
      final int autoRetryTimes,
      final boolean forceReDownload,
      final FileDownloadHeader header) {
    final int id = FileDownloadUtils.generateId(url, path, pathAsDirectory);
    FileDownloadModel model = mHelper.find(id);

    if (!pathAsDirectory && model == null) {
      // try dir data.
      final int dirCaseId =
          FileDownloadUtils.generateId(url, FileDownloadUtils.getParent(path), true);
      model = mHelper.find(dirCaseId);
      if (model != null && path.equals(model.getTargetFilePath())) {
        if (FileDownloadLog.NEED_LOG) {
          FileDownloadLog.d(this, "task[%d] find model by dirCaseId[%d]", id, dirCaseId);
        }
      }
    }

    if (FileDownloadHelper.inspectAndInflowDownloading(id, model, this)) {
      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(this, "has already started download %d", id);
      }
      return;
    }

    final String targetFilePath =
        model != null
            ? model.getTargetFilePath()
            : FileDownloadUtils.getTargetFilePath(path, pathAsDirectory, null);

    if (FileDownloadHelper.inspectAndInflowDownloaded(id, targetFilePath, forceReDownload)) {
      if (FileDownloadLog.NEED_LOG) {
        FileDownloadLog.d(this, "has already completed downloading %d", id);
      }
      return;
    }

    // real start
    // - create model
    boolean needUpdate2DB;
    if (model != null
        && (model.getStatus() == FileDownloadStatus.paused
            || model.getStatus() == FileDownloadStatus.error) // FileDownloadRunnable invoke
    // #isBreakpointAvailable to determine whether it is really invalid.
    ) {
      if (model.getId() != id) {
        // in try dir case.
        mHelper.remove(model.getId());
        model.setId(id);
        model.setPath(path, pathAsDirectory);

        needUpdate2DB = true;
      } else {
        needUpdate2DB = false;
      }
    } else {
      if (model == null) {
        model = new FileDownloadModel();
      }
      model.setUrl(url);
      model.setPath(path, pathAsDirectory);

      model.setId(id);
      model.setSoFar(0);
      model.setTotal(0);
      model.setStatus(FileDownloadStatus.pending);
      needUpdate2DB = true;
    }

    // - update model to db
    if (needUpdate2DB) {
      mHelper.update(model);
    }

    // - execute
    mThreadPool.execute(
        new FileDownloadRunnable(
            client,
            this,
            model,
            mHelper,
            autoRetryTimes,
            header,
            callbackProgressMinIntervalMillis,
            callbackProgressTimes,
            forceReDownload));
  }
コード例 #30
0
 /**
  * Just cache ApplicationContext
  *
  * <p>Proposed call at{@link Application#onCreate()}
  */
 public static void init(final Application application) {
   if (FileDownloadLog.NEED_LOG) {
     FileDownloadLog.d(FileDownloader.class, "init Downloader");
   }
   FileDownloadHelper.initAppContext(application);
 }