parent
							
								
									c9eb57132b
								
							
						
					
					
						commit
						1e237d795d
					
				@ -0,0 +1,167 @@ | 
				
			||||
/* | 
				
			||||
 * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
 | 
				
			||||
 * | 
				
			||||
 * Licensed under the Apache License, Version 2.0 (the "License"); | 
				
			||||
 * you may not use this file except in compliance with the License. | 
				
			||||
 * You may obtain a copy of the License at | 
				
			||||
 * | 
				
			||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||
 * | 
				
			||||
 * Unless required by applicable law or agreed to in writing, software | 
				
			||||
 * distributed under the License is distributed on an "AS IS" BASIS, | 
				
			||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
				
			||||
 * See the License for the specific language governing permissions and | 
				
			||||
 * limitations under the License. | 
				
			||||
 */ | 
				
			||||
package com.arialyy.aria.http; | 
				
			||||
 | 
				
			||||
import com.arialyy.aria.core.common.AbsEntity; | 
				
			||||
import com.arialyy.aria.core.common.CompleteInfo; | 
				
			||||
import com.arialyy.aria.core.download.DGTaskWrapper; | 
				
			||||
import com.arialyy.aria.core.download.DTaskWrapper; | 
				
			||||
import com.arialyy.aria.core.download.DownloadEntity; | 
				
			||||
import com.arialyy.aria.core.listener.DownloadGroupListener; | 
				
			||||
import com.arialyy.aria.core.loader.IInfoTask; | 
				
			||||
import com.arialyy.aria.core.loader.ILoaderVisitor; | 
				
			||||
import com.arialyy.aria.exception.AriaIOException; | 
				
			||||
import com.arialyy.aria.exception.BaseException; | 
				
			||||
import com.arialyy.aria.util.ALog; | 
				
			||||
import com.arialyy.aria.util.CommonUtil; | 
				
			||||
import java.util.concurrent.ExecutorService; | 
				
			||||
import java.util.concurrent.Executors; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * 组合任务文件信息,用于获取长度未知时,组合任务的长度 | 
				
			||||
 */ | 
				
			||||
public class HttpGroupInfoTask implements IInfoTask { | 
				
			||||
  private String TAG = CommonUtil.getClassName(this); | 
				
			||||
  private Callback callback; | 
				
			||||
  private DGTaskWrapper wrapper; | 
				
			||||
  private final Object LOCK = new Object(); | 
				
			||||
  private ExecutorService mPool = null; | 
				
			||||
  private boolean getLenComplete = false; | 
				
			||||
  private int count; | 
				
			||||
  private int failCount; | 
				
			||||
  private DownloadGroupListener listener; | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * 子任务回调 | 
				
			||||
   */ | 
				
			||||
  private Callback subCallback = new Callback() { | 
				
			||||
    @Override public void onSucceed(String url, CompleteInfo info) { | 
				
			||||
      count++; | 
				
			||||
      checkGetSizeComplete(count, failCount); | 
				
			||||
      ALog.d(TAG, "获取子任务信息完成"); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    @Override public void onFail(AbsEntity entity, BaseException e, boolean needRetry) { | 
				
			||||
      ALog.e(TAG, String.format("获取文件信息失败,url:%s", ((DownloadEntity) entity).getUrl())); | 
				
			||||
      count++; | 
				
			||||
      failCount++; | 
				
			||||
      listener.onSubFail((DownloadEntity) entity, new AriaIOException(TAG, | 
				
			||||
          String.format("子任务获取文件长度失败,url:%s", ((DownloadEntity) entity).getUrl()))); | 
				
			||||
      checkGetSizeComplete(count, failCount); | 
				
			||||
    } | 
				
			||||
  }; | 
				
			||||
 | 
				
			||||
  public HttpGroupInfoTask(DGTaskWrapper wrapper, DownloadGroupListener listener) { | 
				
			||||
    this.wrapper = wrapper; | 
				
			||||
    this.listener = listener; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public void run() { | 
				
			||||
    // 如果是isUnknownSize()标志,并且获取大小没有完成,则直接回调onStop
 | 
				
			||||
    if (mPool != null && !getLenComplete) { | 
				
			||||
      ALog.d(TAG, "获取长度未完成的情况下,停止组合任务"); | 
				
			||||
      mPool.shutdown(); | 
				
			||||
      //mListener.onStop(0);
 | 
				
			||||
      return; | 
				
			||||
    } | 
				
			||||
    // 处理组合任务大小未知的情况
 | 
				
			||||
    if (wrapper.isUnknownSize() && wrapper.getEntity().getFileSize() < 1) { | 
				
			||||
      mPool = Executors.newCachedThreadPool(); | 
				
			||||
      getGroupSize(); | 
				
			||||
      try { | 
				
			||||
        synchronized (LOCK) { | 
				
			||||
          LOCK.wait(); | 
				
			||||
        } | 
				
			||||
      } catch (InterruptedException e) { | 
				
			||||
        e.printStackTrace(); | 
				
			||||
      } | 
				
			||||
    } else { | 
				
			||||
      for (DTaskWrapper wrapper : wrapper.getSubTaskWrapper()) { | 
				
			||||
        cloneHeader(wrapper); | 
				
			||||
      } | 
				
			||||
      callback.onSucceed(wrapper.getKey(), new CompleteInfo()); | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * 获取组合任务大小,使用该方式获取到的组合任务大小,子任务不需要再重新获取文件大小 | 
				
			||||
   */ | 
				
			||||
  private void getGroupSize() { | 
				
			||||
    new Thread(new Runnable() { | 
				
			||||
      @Override public void run() { | 
				
			||||
        for (DTaskWrapper dTaskWrapper : wrapper.getSubTaskWrapper()) { | 
				
			||||
          cloneHeader(dTaskWrapper); | 
				
			||||
          HttpFileInfoTask infoTask = new HttpFileInfoTask(dTaskWrapper); | 
				
			||||
          infoTask.setCallback(subCallback); | 
				
			||||
        } | 
				
			||||
      } | 
				
			||||
    }).start(); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * 检查组合任务大小是否获取完成,获取完成后取消阻塞,并设置组合任务大小 | 
				
			||||
   */ | 
				
			||||
  private void checkGetSizeComplete(int count, int failCount) { | 
				
			||||
    if (failCount == wrapper.getSubTaskWrapper().size()) { | 
				
			||||
      callback.onFail(wrapper.getEntity(), new AriaIOException(TAG, "获取子任务长度失败"), false); | 
				
			||||
      notifyLock(); | 
				
			||||
      return; | 
				
			||||
    } | 
				
			||||
    if (count == wrapper.getSubTaskWrapper().size()) { | 
				
			||||
      long size = 0; | 
				
			||||
      for (DTaskWrapper wrapper : wrapper.getSubTaskWrapper()) { | 
				
			||||
        size += wrapper.getEntity().getFileSize(); | 
				
			||||
      } | 
				
			||||
      wrapper.getEntity().setConvertFileSize(CommonUtil.formatFileSize(size)); | 
				
			||||
      wrapper.getEntity().setFileSize(size); | 
				
			||||
      wrapper.getEntity().update(); | 
				
			||||
      getLenComplete = true; | 
				
			||||
      ALog.d(TAG, String.format("获取组合任务长度完成,组合任务总长度:%s,失败的只任务数:%s", size, failCount)); | 
				
			||||
      callback.onSucceed(wrapper.getKey(), new CompleteInfo()); | 
				
			||||
      notifyLock(); | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  private void notifyLock() { | 
				
			||||
    synchronized (LOCK) { | 
				
			||||
      LOCK.notifyAll(); | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * 子任务使用父包裹器的属性 | 
				
			||||
   */ | 
				
			||||
  private void cloneHeader(DTaskWrapper taskWrapper) { | 
				
			||||
    HttpTaskOption groupOption = (HttpTaskOption) wrapper.getTaskOption(); | 
				
			||||
    HttpTaskOption subOption = new HttpTaskOption(); | 
				
			||||
 | 
				
			||||
    // 设置属性
 | 
				
			||||
    subOption.setFileLenAdapter(groupOption.getFileLenAdapter()); | 
				
			||||
    subOption.setRequestEnum(groupOption.getRequestEnum()); | 
				
			||||
    subOption.setHeaders(groupOption.getHeaders()); | 
				
			||||
    subOption.setProxy(groupOption.getProxy()); | 
				
			||||
    subOption.setParams(groupOption.getParams()); | 
				
			||||
    taskWrapper.setTaskOption(subOption); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public void setCallback(Callback callback) { | 
				
			||||
    this.callback = callback; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public void accept(ILoaderVisitor visitor) { | 
				
			||||
    visitor.addComponent(this); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
@ -1,100 +1,100 @@ | 
				
			||||
/* | 
				
			||||
 * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
 | 
				
			||||
 * | 
				
			||||
 * Licensed under the Apache License, Version 2.0 (the "License"); | 
				
			||||
 * you may not use this file except in compliance with the License. | 
				
			||||
 * You may obtain a copy of the License at | 
				
			||||
 * | 
				
			||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||
 * | 
				
			||||
 * Unless required by applicable law or agreed to in writing, software | 
				
			||||
 * distributed under the License is distributed on an "AS IS" BASIS, | 
				
			||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
				
			||||
 * See the License for the specific language governing permissions and | 
				
			||||
 * limitations under the License. | 
				
			||||
 */ | 
				
			||||
package com.arialyy.aria.http.download; | 
				
			||||
 | 
				
			||||
import com.arialyy.aria.core.TaskRecord; | 
				
			||||
import com.arialyy.aria.core.common.RecordHandler; | 
				
			||||
import com.arialyy.aria.core.common.SubThreadConfig; | 
				
			||||
import com.arialyy.aria.core.download.DownloadEntity; | 
				
			||||
import com.arialyy.aria.core.inf.IRecordHandler; | 
				
			||||
import com.arialyy.aria.core.task.AbsNormalLoaderAdapter; | 
				
			||||
import com.arialyy.aria.core.task.IThreadTask; | 
				
			||||
import com.arialyy.aria.core.task.ThreadTask; | 
				
			||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; | 
				
			||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; | 
				
			||||
import com.arialyy.aria.http.HttpRecordAdapter; | 
				
			||||
import com.arialyy.aria.util.ALog; | 
				
			||||
import com.arialyy.aria.util.BufferedRandomAccessFile; | 
				
			||||
import com.arialyy.aria.util.FileUtil; | 
				
			||||
import java.io.File; | 
				
			||||
import java.io.IOException; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * @Author lyy | 
				
			||||
 * @Date 2019-09-21 | 
				
			||||
 */ | 
				
			||||
final class HttpDLoaderAdapter extends AbsNormalLoaderAdapter { | 
				
			||||
  HttpDLoaderAdapter(ITaskWrapper wrapper) { | 
				
			||||
    super(wrapper); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { | 
				
			||||
    if (!record.isBlock) { | 
				
			||||
      if (getTempFile().exists()) { | 
				
			||||
        FileUtil.deleteFile(getTempFile()); | 
				
			||||
      } | 
				
			||||
    } else { | 
				
			||||
      for (int i = 0; i < totalThreadNum; i++) { | 
				
			||||
        File blockFile = | 
				
			||||
            new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i)); | 
				
			||||
        if (blockFile.exists()) { | 
				
			||||
          ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i)); | 
				
			||||
          FileUtil.deleteFile(blockFile); | 
				
			||||
        } | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
    BufferedRandomAccessFile file = null; | 
				
			||||
    try { | 
				
			||||
      if (totalThreadNum > 1 && !record.isBlock) { | 
				
			||||
        file = new BufferedRandomAccessFile(new File(getTempFile().getPath()), "rwd", 8192); | 
				
			||||
        //设置文件长度
 | 
				
			||||
        file.setLength(getEntity().getFileSize()); | 
				
			||||
      } | 
				
			||||
      return true; | 
				
			||||
    } catch (IOException e) { | 
				
			||||
      e.printStackTrace(); | 
				
			||||
      ALog.e(TAG, String.format("下载失败,filePath: %s, url: %s", getEntity().getFilePath(), | 
				
			||||
          getEntity().getUrl())); | 
				
			||||
    } finally { | 
				
			||||
      if (file != null) { | 
				
			||||
        try { | 
				
			||||
          file.close(); | 
				
			||||
        } catch (IOException e) { | 
				
			||||
          e.printStackTrace(); | 
				
			||||
        } | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
    return false; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public IThreadTask createThreadTask(SubThreadConfig config) { | 
				
			||||
    ThreadTask task = new ThreadTask(config); | 
				
			||||
    HttpDThreadTaskAdapter adapter = new HttpDThreadTaskAdapter(config); | 
				
			||||
    task.setAdapter(adapter); | 
				
			||||
    return task; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) { | 
				
			||||
    RecordHandler recordHandler = new RecordHandler(wrapper); | 
				
			||||
    HttpRecordAdapter adapter = new HttpRecordAdapter(wrapper); | 
				
			||||
    recordHandler.setAdapter(adapter); | 
				
			||||
    return recordHandler; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  private DownloadEntity getEntity() { | 
				
			||||
    return (DownloadEntity) getWrapper().getEntity(); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
///*
 | 
				
			||||
// * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
 | 
				
			||||
// *
 | 
				
			||||
// * Licensed under the Apache License, Version 2.0 (the "License");
 | 
				
			||||
// * you may not use this file except in compliance with the License.
 | 
				
			||||
// * You may obtain a copy of the License at
 | 
				
			||||
// *
 | 
				
			||||
// *      http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||
// *
 | 
				
			||||
// * Unless required by applicable law or agreed to in writing, software
 | 
				
			||||
// * distributed under the License is distributed on an "AS IS" BASIS,
 | 
				
			||||
// * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
				
			||||
// * See the License for the specific language governing permissions and
 | 
				
			||||
// * limitations under the License.
 | 
				
			||||
// */
 | 
				
			||||
//package com.arialyy.aria.http.download;
 | 
				
			||||
//
 | 
				
			||||
//import com.arialyy.aria.core.TaskRecord;
 | 
				
			||||
//import com.arialyy.aria.core.common.RecordHandler;
 | 
				
			||||
//import com.arialyy.aria.core.common.SubThreadConfig;
 | 
				
			||||
//import com.arialyy.aria.core.download.DownloadEntity;
 | 
				
			||||
//import com.arialyy.aria.core.loader.IRecordHandler;
 | 
				
			||||
//import com.arialyy.aria.core.task.AbsNormalLoaderAdapter;
 | 
				
			||||
//import com.arialyy.aria.core.task.IThreadTask;
 | 
				
			||||
//import com.arialyy.aria.core.task.ThreadTask;
 | 
				
			||||
//import com.arialyy.aria.core.wrapper.AbsTaskWrapper;
 | 
				
			||||
//import com.arialyy.aria.core.wrapper.ITaskWrapper;
 | 
				
			||||
//import com.arialyy.aria.http.HttpRecordHandler;
 | 
				
			||||
//import com.arialyy.aria.util.ALog;
 | 
				
			||||
//import com.arialyy.aria.util.BufferedRandomAccessFile;
 | 
				
			||||
//import com.arialyy.aria.util.FileUtil;
 | 
				
			||||
//import java.io.File;
 | 
				
			||||
//import java.io.IOException;
 | 
				
			||||
//
 | 
				
			||||
///**
 | 
				
			||||
// * @Author lyy
 | 
				
			||||
// * @Date 2019-09-21
 | 
				
			||||
// */
 | 
				
			||||
//final class HttpDLoaderAdapter extends AbsNormalLoaderAdapter {
 | 
				
			||||
//  HttpDLoaderAdapter(ITaskWrapper wrapper) {
 | 
				
			||||
//    super(wrapper);
 | 
				
			||||
//  }
 | 
				
			||||
//
 | 
				
			||||
//  @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) {
 | 
				
			||||
//    if (!record.isBlock) {
 | 
				
			||||
//      if (getTempFile().exists()) {
 | 
				
			||||
//        FileUtil.deleteFile(getTempFile());
 | 
				
			||||
//      }
 | 
				
			||||
//    } else {
 | 
				
			||||
//      for (int i = 0; i < totalThreadNum; i++) {
 | 
				
			||||
//        File blockFile =
 | 
				
			||||
//            new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i));
 | 
				
			||||
//        if (blockFile.exists()) {
 | 
				
			||||
//          ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i));
 | 
				
			||||
//          FileUtil.deleteFile(blockFile);
 | 
				
			||||
//        }
 | 
				
			||||
//      }
 | 
				
			||||
//    }
 | 
				
			||||
//    BufferedRandomAccessFile file = null;
 | 
				
			||||
//    try {
 | 
				
			||||
//      if (totalThreadNum > 1 && !record.isBlock) {
 | 
				
			||||
//        file = new BufferedRandomAccessFile(new File(getTempFile().getPath()), "rwd", 8192);
 | 
				
			||||
//        //设置文件长度
 | 
				
			||||
//        file.setLength(getEntity().getFileSize());
 | 
				
			||||
//      }
 | 
				
			||||
//      return true;
 | 
				
			||||
//    } catch (IOException e) {
 | 
				
			||||
//      e.printStackTrace();
 | 
				
			||||
//      ALog.e(TAG, String.format("下载失败,filePath: %s, url: %s", getEntity().getFilePath(),
 | 
				
			||||
//          getEntity().getUrl()));
 | 
				
			||||
//    } finally {
 | 
				
			||||
//      if (file != null) {
 | 
				
			||||
//        try {
 | 
				
			||||
//          file.close();
 | 
				
			||||
//        } catch (IOException e) {
 | 
				
			||||
//          e.printStackTrace();
 | 
				
			||||
//        }
 | 
				
			||||
//      }
 | 
				
			||||
//    }
 | 
				
			||||
//    return false;
 | 
				
			||||
//  }
 | 
				
			||||
//
 | 
				
			||||
//  @Override public IThreadTask createThreadTask(SubThreadConfig config) {
 | 
				
			||||
//    ThreadTask task = new ThreadTask(config);
 | 
				
			||||
//    HttpDThreadTaskAdapter adapter = new HttpDThreadTaskAdapter(config);
 | 
				
			||||
//    task.setAdapter(adapter);
 | 
				
			||||
//    return task;
 | 
				
			||||
//  }
 | 
				
			||||
//
 | 
				
			||||
//  @Override public IRecordHandler recordHandler(AbsTaskWrapper wrapper) {
 | 
				
			||||
//    RecordHandler recordHandler = new RecordHandler(wrapper);
 | 
				
			||||
//    HttpRecordHandler adapter = new HttpRecordHandler(wrapper);
 | 
				
			||||
//    recordHandler.setAdapter(adapter);
 | 
				
			||||
//    return recordHandler;
 | 
				
			||||
//  }
 | 
				
			||||
//
 | 
				
			||||
//  private DownloadEntity getEntity() {
 | 
				
			||||
//    return (DownloadEntity) getWrapper().getEntity();
 | 
				
			||||
//  }
 | 
				
			||||
//}
 | 
				
			||||
 | 
				
			||||
@ -0,0 +1,62 @@ | 
				
			||||
package com.arialyy.aria.http.download; | 
				
			||||
 | 
				
			||||
import com.arialyy.aria.core.TaskRecord; | 
				
			||||
import com.arialyy.aria.core.common.SubThreadConfig; | 
				
			||||
import com.arialyy.aria.core.loader.AbsNormalTTBuilder; | 
				
			||||
import com.arialyy.aria.core.loader.IRecordHandler; | 
				
			||||
import com.arialyy.aria.core.task.IThreadTaskAdapter; | 
				
			||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; | 
				
			||||
import com.arialyy.aria.util.ALog; | 
				
			||||
import com.arialyy.aria.util.BufferedRandomAccessFile; | 
				
			||||
import com.arialyy.aria.util.FileUtil; | 
				
			||||
import java.io.File; | 
				
			||||
import java.io.IOException; | 
				
			||||
 | 
				
			||||
final class HttpDTTBuilder extends AbsNormalTTBuilder { | 
				
			||||
  HttpDTTBuilder(AbsTaskWrapper wrapper) { | 
				
			||||
    super(wrapper); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public IThreadTaskAdapter getAdapter(SubThreadConfig config) { | 
				
			||||
    return new HttpDThreadTaskAdapter(config); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public boolean handleNewTask(TaskRecord record, int totalThreadNum) { | 
				
			||||
    if (!record.isBlock) { | 
				
			||||
      if (getTempFile().exists()) { | 
				
			||||
        FileUtil.deleteFile(getTempFile()); | 
				
			||||
      } | 
				
			||||
    } else { | 
				
			||||
      for (int i = 0; i < totalThreadNum; i++) { | 
				
			||||
        File blockFile = | 
				
			||||
            new File(String.format(IRecordHandler.SUB_PATH, getTempFile().getPath(), i)); | 
				
			||||
        if (blockFile.exists()) { | 
				
			||||
          ALog.d(TAG, String.format("分块【%s】已经存在,将删除该分块", i)); | 
				
			||||
          FileUtil.deleteFile(blockFile); | 
				
			||||
        } | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
    BufferedRandomAccessFile file = null; | 
				
			||||
    try { | 
				
			||||
      if (totalThreadNum > 1 && !record.isBlock) { | 
				
			||||
        file = new BufferedRandomAccessFile(new File(getTempFile().getPath()), "rwd", 8192); | 
				
			||||
        //设置文件长度
 | 
				
			||||
        file.setLength(getEntity().getFileSize()); | 
				
			||||
      } | 
				
			||||
      return true; | 
				
			||||
    } catch (IOException e) { | 
				
			||||
      e.printStackTrace(); | 
				
			||||
      ALog.e(TAG, String.format("下载失败,filePath: %s, url: %s", getEntity().getFilePath(), | 
				
			||||
          getEntity().getUrl())); | 
				
			||||
    } finally { | 
				
			||||
      if (file != null) { | 
				
			||||
        try { | 
				
			||||
          file.close(); | 
				
			||||
        } catch (IOException e) { | 
				
			||||
          e.printStackTrace(); | 
				
			||||
        } | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
    return false; | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
@ -1,44 +0,0 @@ | 
				
			||||
/* | 
				
			||||
 * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
 | 
				
			||||
 * | 
				
			||||
 * Licensed under the Apache License, Version 2.0 (the "License"); | 
				
			||||
 * you may not use this file except in compliance with the License. | 
				
			||||
 * You may obtain a copy of the License at | 
				
			||||
 * | 
				
			||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||
 * | 
				
			||||
 * Unless required by applicable law or agreed to in writing, software | 
				
			||||
 * distributed under the License is distributed on an "AS IS" BASIS, | 
				
			||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
				
			||||
 * See the License for the specific language governing permissions and | 
				
			||||
 * limitations under the License. | 
				
			||||
 */ | 
				
			||||
package com.arialyy.aria.core.common; | 
				
			||||
 | 
				
			||||
import com.arialyy.aria.core.inf.IRecordHandlerAdapter; | 
				
			||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; | 
				
			||||
import com.arialyy.aria.util.CommonUtil; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * @Author lyy | 
				
			||||
 * @Date 2019-09-19 | 
				
			||||
 */ | 
				
			||||
public abstract class AbsRecordHandlerAdapter implements IRecordHandlerAdapter { | 
				
			||||
  private AbsTaskWrapper mWrapper; | 
				
			||||
  protected String TAG = CommonUtil.getClassName(getClass()); | 
				
			||||
 | 
				
			||||
  @Override public void onPre() { | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  public AbsRecordHandlerAdapter(AbsTaskWrapper wrapper) { | 
				
			||||
    mWrapper = wrapper; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  public AbsTaskWrapper getWrapper() { | 
				
			||||
    return mWrapper; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  protected AbsNormalEntity getEntity() { | 
				
			||||
    return (AbsNormalEntity) getWrapper().getEntity(); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
@ -0,0 +1,185 @@ | 
				
			||||
package com.arialyy.aria.core.loader; | 
				
			||||
 | 
				
			||||
import android.os.Handler; | 
				
			||||
import android.os.Looper; | 
				
			||||
import com.arialyy.aria.core.TaskRecord; | 
				
			||||
import com.arialyy.aria.core.ThreadRecord; | 
				
			||||
import com.arialyy.aria.core.common.AbsNormalEntity; | 
				
			||||
import com.arialyy.aria.core.common.SubThreadConfig; | 
				
			||||
import com.arialyy.aria.core.download.DGTaskWrapper; | 
				
			||||
import com.arialyy.aria.core.inf.IThreadState; | 
				
			||||
import com.arialyy.aria.core.task.IThreadTask; | 
				
			||||
import com.arialyy.aria.core.task.IThreadTaskAdapter; | 
				
			||||
import com.arialyy.aria.core.task.ThreadTask; | 
				
			||||
import com.arialyy.aria.core.wrapper.AbsTaskWrapper; | 
				
			||||
import com.arialyy.aria.util.ALog; | 
				
			||||
import com.arialyy.aria.util.CommonUtil; | 
				
			||||
import java.io.File; | 
				
			||||
import java.util.ArrayList; | 
				
			||||
import java.util.List; | 
				
			||||
 | 
				
			||||
public abstract class AbsNormalTTBuilder implements IThreadTaskBuilder { | 
				
			||||
  protected String TAG = CommonUtil.getClassName(this); | 
				
			||||
 | 
				
			||||
  private Handler mStateHandler; | 
				
			||||
  private AbsTaskWrapper mWrapper; | 
				
			||||
  private TaskRecord mRecord; | 
				
			||||
  private int mTotalThreadNum; | 
				
			||||
  private File mTempFile; | 
				
			||||
  private int mStartThreadNum; | 
				
			||||
 | 
				
			||||
  public AbsNormalTTBuilder(AbsTaskWrapper wrapper) { | 
				
			||||
    if (wrapper instanceof DGTaskWrapper) { | 
				
			||||
      throw new AssertionError("NormalTTBuilder 不适用于组合任务"); | 
				
			||||
    } | 
				
			||||
    mWrapper = wrapper; | 
				
			||||
    mTempFile = new File(((AbsNormalEntity) wrapper.getEntity()).getFilePath()); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  protected File getTempFile(){ | 
				
			||||
    return mTempFile; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  protected AbsNormalEntity getEntity() { | 
				
			||||
    return (AbsNormalEntity) mWrapper.getEntity(); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * 创建线程任务适配器 | 
				
			||||
   */ | 
				
			||||
  public abstract IThreadTaskAdapter getAdapter(SubThreadConfig config); | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * 处理新任务 | 
				
			||||
   * | 
				
			||||
   * @param record 任务记录 | 
				
			||||
   * @param totalThreadNum 任务的线程总数 | 
				
			||||
   * @return {@code true}创建新任务成功 | 
				
			||||
   */ | 
				
			||||
  public abstract boolean handleNewTask(TaskRecord record, int totalThreadNum); | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * 创建线程任务 | 
				
			||||
   */ | 
				
			||||
  private IThreadTask createThreadTask(SubThreadConfig config) { | 
				
			||||
    ThreadTask task = new ThreadTask(config); | 
				
			||||
    task.setAdapter(getAdapter(config)); | 
				
			||||
    return task; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * 启动断点任务时,创建单线程任务 | 
				
			||||
   * | 
				
			||||
   * @param record 线程记录 | 
				
			||||
   * @param startNum 启动的线程数 | 
				
			||||
   */ | 
				
			||||
  private IThreadTask createSingThreadTask(ThreadRecord record, int startNum) { | 
				
			||||
    SubThreadConfig config = new SubThreadConfig(); | 
				
			||||
    config.url = getEntity().isRedirect() ? getEntity().getRedirectUrl() : getEntity().getUrl(); | 
				
			||||
    config.tempFile = | 
				
			||||
        mRecord.isBlock ? new File( | 
				
			||||
            String.format(IRecordHandler.SUB_PATH, mTempFile.getPath(), record.threadId)) | 
				
			||||
            : mTempFile; | 
				
			||||
    config.isBlock = mRecord.isBlock; | 
				
			||||
    config.startThreadNum = startNum; | 
				
			||||
    config.taskWrapper = mWrapper; | 
				
			||||
    config.record = record; | 
				
			||||
    config.stateHandler = mStateHandler; | 
				
			||||
    return createThreadTask(config); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * 处理不支持断点的任务 | 
				
			||||
   */ | 
				
			||||
  private List<IThreadTask> handleNoSupportBP() { | 
				
			||||
    List<IThreadTask> list = new ArrayList<>(); | 
				
			||||
    mStartThreadNum = 1; | 
				
			||||
 | 
				
			||||
    IThreadTask task = createSingThreadTask(mRecord.threadRecords.get(0), 1); | 
				
			||||
    if (task == null) { | 
				
			||||
      ALog.e(TAG, "创建线程任务失败"); | 
				
			||||
      return null; | 
				
			||||
    } | 
				
			||||
    list.add(task); | 
				
			||||
    return list; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  /** | 
				
			||||
   * 处理支持断点的任务 | 
				
			||||
   */ | 
				
			||||
  private List<IThreadTask> handleBreakpoint() { | 
				
			||||
    long fileLength = getEntity().getFileSize(); | 
				
			||||
    long blockSize = fileLength / mTotalThreadNum; | 
				
			||||
    long currentProgress = 0; | 
				
			||||
    List<IThreadTask> threadTasks = new ArrayList<>(); | 
				
			||||
 | 
				
			||||
    mRecord.fileLength = fileLength; | 
				
			||||
    if (mWrapper.isNewTask() && !handleNewTask(mRecord, mTotalThreadNum)) { | 
				
			||||
      ALog.e(TAG, "初始化线程任务失败"); | 
				
			||||
      return null; | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    for (ThreadRecord tr : mRecord.threadRecords) { | 
				
			||||
      if (!tr.isComplete) { | 
				
			||||
        mStartThreadNum++; | 
				
			||||
      } | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    for (int i = 0; i < mTotalThreadNum; i++) { | 
				
			||||
      long startL = i * blockSize, endL = (i + 1) * blockSize; | 
				
			||||
      ThreadRecord tr = mRecord.threadRecords.get(i); | 
				
			||||
 | 
				
			||||
      if (tr.isComplete) {//该线程已经完成
 | 
				
			||||
        currentProgress += endL - startL; | 
				
			||||
        ALog.d(TAG, String.format("任务【%s】线程__%s__已完成", mWrapper.getKey(), i)); | 
				
			||||
        mStateHandler.obtainMessage(IThreadState.STATE_COMPLETE).sendToTarget(); | 
				
			||||
        continue; | 
				
			||||
      } | 
				
			||||
 | 
				
			||||
      //如果有记录,则恢复任务
 | 
				
			||||
      long r = tr.startLocation; | 
				
			||||
      //记录的位置需要在线程区间中
 | 
				
			||||
      if (startL < r && r <= (i == (mTotalThreadNum - 1) ? fileLength : endL)) { | 
				
			||||
        currentProgress += r - startL; | 
				
			||||
      } | 
				
			||||
      ALog.d(TAG, String.format("任务【%s】线程__%s__恢复任务", getEntity().getFileName(), i)); | 
				
			||||
 | 
				
			||||
      IThreadTask task = createSingThreadTask(tr, mStartThreadNum); | 
				
			||||
      if (task == null) { | 
				
			||||
        ALog.e(TAG, "创建线程任务失败"); | 
				
			||||
        return null; | 
				
			||||
      } | 
				
			||||
      threadTasks.add(task); | 
				
			||||
    } | 
				
			||||
    if (currentProgress != 0 && currentProgress != getEntity().getCurrentProgress()) { | 
				
			||||
      ALog.d(TAG, String.format("进度修正,当前进度:%s", currentProgress)); | 
				
			||||
      getEntity().setCurrentProgress(currentProgress); | 
				
			||||
    } | 
				
			||||
    //mStateManager.updateProgress(currentProgress);
 | 
				
			||||
    return threadTasks; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  private List<IThreadTask> handleTask() { | 
				
			||||
    if (mWrapper.isSupportBP()) { | 
				
			||||
      return handleBreakpoint(); | 
				
			||||
    }else { | 
				
			||||
      return handleNoSupportBP(); | 
				
			||||
    } | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public List<IThreadTask> buildThreadTask(TaskRecord record, Looper looper, | 
				
			||||
      IThreadState stateManager) { | 
				
			||||
    mRecord = record; | 
				
			||||
    mStateHandler = new Handler(looper, stateManager.getHandlerCallback()); | 
				
			||||
    mTotalThreadNum = mRecord.threadNum; | 
				
			||||
    return handleTask(); | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public int getCreatedThreadNum() { | 
				
			||||
    return mStartThreadNum; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public void accept(ILoaderVisitor visitor) { | 
				
			||||
    visitor.addComponent(this); | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
@ -1,75 +0,0 @@ | 
				
			||||
/* | 
				
			||||
 * Copyright (C) 2016 AriaLyy(https://github.com/AriaLyy/Aria)
 | 
				
			||||
 * | 
				
			||||
 * Licensed under the Apache License, Version 2.0 (the "License"); | 
				
			||||
 * you may not use this file except in compliance with the License. | 
				
			||||
 * You may obtain a copy of the License at | 
				
			||||
 * | 
				
			||||
 *      http://www.apache.org/licenses/LICENSE-2.0
 | 
				
			||||
 * | 
				
			||||
 * Unless required by applicable law or agreed to in writing, software | 
				
			||||
 * distributed under the License is distributed on an "AS IS" BASIS, | 
				
			||||
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
				
			||||
 * See the License for the specific language governing permissions and | 
				
			||||
 * limitations under the License. | 
				
			||||
 */ | 
				
			||||
package com.arialyy.aria.core.loader; | 
				
			||||
 | 
				
			||||
import com.arialyy.aria.core.TaskRecord; | 
				
			||||
import com.arialyy.aria.core.listener.IEventListener; | 
				
			||||
import com.arialyy.aria.core.wrapper.ITaskWrapper; | 
				
			||||
import java.util.List; | 
				
			||||
 | 
				
			||||
/** | 
				
			||||
 * 责任链 | 
				
			||||
 */ | 
				
			||||
public final class LoaderChain implements ILoaderInterceptor.Chain { | 
				
			||||
  private ITaskWrapper wrapper; | 
				
			||||
  private IEventListener listener; | 
				
			||||
  private TaskRecord taskRecord; | 
				
			||||
  private int index; | 
				
			||||
  private List<ILoaderInterceptor> interceptors; | 
				
			||||
 | 
				
			||||
  public LoaderChain(List<ILoaderInterceptor> interceptors, ITaskWrapper wrapper, | 
				
			||||
      IEventListener listener, TaskRecord taskRecord, | 
				
			||||
      int index) { | 
				
			||||
    this.interceptors = interceptors; | 
				
			||||
    this.wrapper = wrapper; | 
				
			||||
    this.listener = listener; | 
				
			||||
    this.taskRecord = taskRecord; | 
				
			||||
    this.index = index; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public void updateRecord(TaskRecord record) { | 
				
			||||
    this.taskRecord = record; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public TaskRecord getRecord() { | 
				
			||||
    return taskRecord; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public IEventListener getListener() { | 
				
			||||
    return listener; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public ITaskWrapper getWrapper() { | 
				
			||||
    return wrapper; | 
				
			||||
  } | 
				
			||||
 | 
				
			||||
  @Override public ILoader proceed() { | 
				
			||||
    int index = this.index + 1; | 
				
			||||
    if (index >= interceptors.size()) { | 
				
			||||
      throw new AssertionError(); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    LoaderChain next = new LoaderChain(interceptors, wrapper, listener, taskRecord, index); | 
				
			||||
    ILoaderInterceptor interceptor = interceptors.get(index); | 
				
			||||
    ILoader loader = interceptor.intercept(next); | 
				
			||||
 | 
				
			||||
    if (loader == null) { | 
				
			||||
      throw new NullPointerException("Loader为空"); | 
				
			||||
    } | 
				
			||||
 | 
				
			||||
    return loader; | 
				
			||||
  } | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue