コード例 #1
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;
  }
コード例 #2
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;
    }
コード例 #3
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);
    }
コード例 #4
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);
  }
コード例 #5
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;
 }
コード例 #6
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));
    }
  }
コード例 #7
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;
  }
コード例 #8
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;
 }
コード例 #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
 // Clear References
 void clear() {
   if (finishListenerList != null) {
     finishListenerList.clear();
   }
   if (FileDownloadLog.NEED_LOG) {
     FileDownloadLog.d(this, "clear %s", this);
   }
 }
コード例 #11
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);
     }
   }
 }
コード例 #12
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;
  }
コード例 #13
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());
  }
コード例 #14
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();
  }
コード例 #15
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);
    }
  }
コード例 #16
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;
  }
コード例 #17
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;
  }
コード例 #18
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;
  }
コード例 #19
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));
  }
コード例 #20
0
 // Clear References
 void clear() {
   if (FileDownloadLog.NEED_LOG) {
     FileDownloadLog.d(this, "clear %s", this);
   }
 }
コード例 #21
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);
 }