Commit 5921ea5942cabfb84d5cc71a06c384a9a4ed5206
0 parents
文件下载基本功能
Showing
57 changed files
with
3154 additions
and
0 deletions
.gitignore
0 → 100644
.idea/caches/build_file_checksums.ser
0 → 100644
No preview for this file type
.idea/caches/gradle_models.ser
0 → 100644
No preview for this file type
.idea/codeStyles/Project.xml
0 → 100644
| 1 | +++ a/.idea/codeStyles/Project.xml | |
| 1 | +<component name="ProjectCodeStyleConfiguration"> | |
| 2 | + <code_scheme name="Project" version="173"> | |
| 3 | + <Objective-C-extensions> | |
| 4 | + <file> | |
| 5 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Import" /> | |
| 6 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Macro" /> | |
| 7 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Typedef" /> | |
| 8 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Enum" /> | |
| 9 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Constant" /> | |
| 10 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Global" /> | |
| 11 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Struct" /> | |
| 12 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="FunctionPredecl" /> | |
| 13 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Function" /> | |
| 14 | + </file> | |
| 15 | + <class> | |
| 16 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Property" /> | |
| 17 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="Synthesize" /> | |
| 18 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InitMethod" /> | |
| 19 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="StaticMethod" /> | |
| 20 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="InstanceMethod" /> | |
| 21 | + <option name="com.jetbrains.cidr.lang.util.OCDeclarationKind" value="DeallocMethod" /> | |
| 22 | + </class> | |
| 23 | + <extensions> | |
| 24 | + <pair source="cpp" header="h" fileNamingConvention="NONE" /> | |
| 25 | + <pair source="c" header="h" fileNamingConvention="NONE" /> | |
| 26 | + </extensions> | |
| 27 | + </Objective-C-extensions> | |
| 28 | + </code_scheme> | |
| 29 | +</component> | |
| 0 | 30 | \ No newline at end of file | ... | ... |
.idea/gradle.xml
0 → 100644
| 1 | +++ a/.idea/gradle.xml | |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<project version="4"> | |
| 3 | + <component name="GradleSettings"> | |
| 4 | + <option name="linkedExternalProjectsSettings"> | |
| 5 | + <GradleProjectSettings> | |
| 6 | + <compositeConfiguration> | |
| 7 | + <compositeBuild compositeDefinitionSource="SCRIPT" /> | |
| 8 | + </compositeConfiguration> | |
| 9 | + <option name="distributionType" value="DEFAULT_WRAPPED" /> | |
| 10 | + <option name="externalProjectPath" value="$PROJECT_DIR$" /> | |
| 11 | + <option name="resolveModulePerSourceSet" value="false" /> | |
| 12 | + </GradleProjectSettings> | |
| 13 | + </option> | |
| 14 | + </component> | |
| 15 | +</project> | |
| 0 | 16 | \ No newline at end of file | ... | ... |
.idea/misc.xml
0 → 100644
| 1 | +++ a/.idea/misc.xml | |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<project version="4"> | |
| 3 | + <component name="CMakeSettings"> | |
| 4 | + <configurations> | |
| 5 | + <configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" /> | |
| 6 | + </configurations> | |
| 7 | + </component> | |
| 8 | + <component name="ProjectRootManager" version="2" languageLevel="JDK_1_7" project-jdk-name="1.8" project-jdk-type="JavaSDK"> | |
| 9 | + <output url="file://$PROJECT_DIR$/build/classes" /> | |
| 10 | + </component> | |
| 11 | + <component name="ProjectType"> | |
| 12 | + <option name="id" value="Android" /> | |
| 13 | + </component> | |
| 14 | +</project> | |
| 0 | 15 | \ No newline at end of file | ... | ... |
.idea/runConfigurations.xml
0 → 100644
| 1 | +++ a/.idea/runConfigurations.xml | |
| 1 | +<?xml version="1.0" encoding="UTF-8"?> | |
| 2 | +<project version="4"> | |
| 3 | + <component name="RunConfigurationProducerService"> | |
| 4 | + <option name="ignoredProducers"> | |
| 5 | + <set> | |
| 6 | + <option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" /> | |
| 7 | + <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" /> | |
| 8 | + <option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" /> | |
| 9 | + </set> | |
| 10 | + </option> | |
| 11 | + </component> | |
| 12 | +</project> | |
| 0 | 13 | \ No newline at end of file | ... | ... |
README.md
0 → 100644
| 1 | +++ a/README.md | |
| 1 | +# DownloadFile | |
| 2 | +Android OkHttp 下载多个文件 断点下载 | |
| 3 | +## 介绍 | |
| 4 | +demo的主要逻辑是,利用okhttp 和 RxJava 在子线程中下载文件,通关观察者模式监听下载的进度,再回调到主线程中,然后利用EventBus 通知页面刷新,更新进度。 | |
| 5 | +## 效果图 | |
| 6 | + | |
| 7 | +### step1 导入依赖库 | |
| 8 | +```Java | |
| 9 | +// OKHttp RxJava | |
| 10 | + implementation 'com.squareup.okhttp3:okhttp:3.6.0' | |
| 11 | + implementation 'io.reactivex.rxjava2:rxjava:2.1.3' | |
| 12 | + implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' | |
| 13 | + // eventbus | |
| 14 | + implementation 'org.greenrobot:eventbus:3.0.0' | |
| 15 | + implementation 'com.android.support:recyclerview-v7:27.1.1' | |
| 16 | +``` | |
| 17 | +### step 2 定义下载bean | |
| 18 | +```Java | |
| 19 | +/** | |
| 20 | + * Created by zs | |
| 21 | + * Date:2018年 09月 12日 | |
| 22 | + * Time:13:50 | |
| 23 | + * ————————————————————————————————————— | |
| 24 | + * About: 下载管理 | |
| 25 | + * ————————————————————————————————————— | |
| 26 | + */ | |
| 27 | +public class DownloadInfo { | |
| 28 | + | |
| 29 | + /** | |
| 30 | + * 下载状态 | |
| 31 | + */ | |
| 32 | + public static final String DOWNLOAD = "download"; | |
| 33 | + public static final String DOWNLOAD_PAUSE = "pause"; | |
| 34 | + public static final String DOWNLOAD_CANCEL = "cancel"; | |
| 35 | + public static final String DOWNLOAD_OVER = "over"; | |
| 36 | + public static final String DOWNLOAD_ERROR = "error"; | |
| 37 | + | |
| 38 | + public static final long TOTAL_ERROR = -1;//获取进度失败 | |
| 39 | + | |
| 40 | + private String url; | |
| 41 | + private String fileName; | |
| 42 | + private String downloadStatus; | |
| 43 | + private long total; | |
| 44 | + private long progress; | |
| 45 | + | |
| 46 | + public DownloadInfo(String url) { | |
| 47 | + this.url = url; | |
| 48 | + } | |
| 49 | + | |
| 50 | + public String getUrl() { | |
| 51 | + return url; | |
| 52 | + } | |
| 53 | + | |
| 54 | + public String getFileName() { | |
| 55 | + return fileName; | |
| 56 | + } | |
| 57 | + | |
| 58 | + public void setFileName(String fileName) { | |
| 59 | + this.fileName = fileName; | |
| 60 | + } | |
| 61 | + | |
| 62 | + public long getTotal() { | |
| 63 | + return total; | |
| 64 | + } | |
| 65 | + | |
| 66 | + public void setTotal(long total) { | |
| 67 | + this.total = total; | |
| 68 | + } | |
| 69 | + | |
| 70 | + public long getProgress() { | |
| 71 | + return progress; | |
| 72 | + } | |
| 73 | + | |
| 74 | + public void setProgress(long progress) { | |
| 75 | + this.progress = progress; | |
| 76 | + } | |
| 77 | + | |
| 78 | + public String getDownloadStatus() { | |
| 79 | + return downloadStatus; | |
| 80 | + } | |
| 81 | + | |
| 82 | + public void setDownloadStatus(String downloadStatus) { | |
| 83 | + this.downloadStatus = downloadStatus; | |
| 84 | + } | |
| 85 | +} | |
| 86 | + | |
| 87 | +``` | |
| 88 | +### step 3 下载管理类 也是主要的内容 (DownloadManager) | |
| 89 | +```Java | |
| 90 | +/** | |
| 91 | + * Created by zs | |
| 92 | + * Date:2018年 09月 12日 | |
| 93 | + * Time:13:56 | |
| 94 | + * ————————————————————————————————————— | |
| 95 | + * About: 下载管理 | |
| 96 | + * ————————————————————————————————————— | |
| 97 | + */ | |
| 98 | +public class DownloadManager { | |
| 99 | + | |
| 100 | + private static final AtomicReference<DownloadManager> INSTANCE = new AtomicReference<>(); | |
| 101 | + private OkHttpClient mClient; | |
| 102 | + private HashMap<String, Call> downCalls; //用来存放各个下载的请求 | |
| 103 | + | |
| 104 | + public static DownloadManager getInstance() { | |
| 105 | + for (; ; ) { | |
| 106 | + DownloadManager current = INSTANCE.get(); | |
| 107 | + if (current != null) { | |
| 108 | + return current; | |
| 109 | + } | |
| 110 | + current = new DownloadManager(); | |
| 111 | + if (INSTANCE.compareAndSet(null, current)) { | |
| 112 | + return current; | |
| 113 | + } | |
| 114 | + } | |
| 115 | + } | |
| 116 | + | |
| 117 | + private DownloadManager() { | |
| 118 | + downCalls = new HashMap<>(); | |
| 119 | + mClient = new OkHttpClient.Builder().build(); | |
| 120 | + } | |
| 121 | + | |
| 122 | + /** | |
| 123 | + * 查看是否在下载任务中 | |
| 124 | + * @param url | |
| 125 | + * @return | |
| 126 | + */ | |
| 127 | + public boolean getDownloadUrl(String url){ | |
| 128 | + return downCalls.containsKey(url); | |
| 129 | + } | |
| 130 | + | |
| 131 | + /** | |
| 132 | + * 开始下载 | |
| 133 | + * | |
| 134 | + * @param url 下载请求的网址 | |
| 135 | + * @param downLoadObserver 用来回调的接口 | |
| 136 | + */ | |
| 137 | + public void download(String url, DownloadObserver downLoadObserver) { | |
| 138 | + | |
| 139 | + Observable.just(url) | |
| 140 | + .filter(new Predicate<String>() { | |
| 141 | + @Override | |
| 142 | + public boolean test(String s) { | |
| 143 | + return !downCalls.containsKey(s); | |
| 144 | + } | |
| 145 | + }) // 过滤 call的map中已经有了,就证明正在下载,则这次不下载 | |
| 146 | + .flatMap(new Function<String, ObservableSource<?>>() { | |
| 147 | + @Override | |
| 148 | + public ObservableSource<?> apply(String s) { | |
| 149 | + return Observable.just(createDownInfo(s)); | |
| 150 | + } | |
| 151 | + }) // 生成 DownloadInfo | |
| 152 | + .map(new Function<Object, DownloadInfo>() { | |
| 153 | + @Override | |
| 154 | + public DownloadInfo apply(Object o) { | |
| 155 | + return getRealFileName((DownloadInfo)o); | |
| 156 | + } | |
| 157 | + }) // 如果已经下载,重新命名 | |
| 158 | + .flatMap(new Function<DownloadInfo, ObservableSource<DownloadInfo>>() { | |
| 159 | + @Override | |
| 160 | + public ObservableSource<DownloadInfo> apply(DownloadInfo downloadInfo) { | |
| 161 | + return Observable.create(new DownloadSubscribe(downloadInfo)); | |
| 162 | + } | |
| 163 | + }) // 下载 | |
| 164 | + .observeOn(AndroidSchedulers.mainThread()) // 在主线程中回调 | |
| 165 | + .subscribeOn(Schedulers.io()) // 在子线程中执行 | |
| 166 | + .subscribe(downLoadObserver); // 添加观察者,监听下载进度 | |
| 167 | + } | |
| 168 | + | |
| 169 | + /** | |
| 170 | + * 下载取消或者暂停 | |
| 171 | + * @param url | |
| 172 | + */ | |
| 173 | + public void pauseDownload(String url) { | |
| 174 | + Call call = downCalls.get(url); | |
| 175 | + if (call != null) { | |
| 176 | + call.cancel();//取消 | |
| 177 | + } | |
| 178 | + downCalls.remove(url); | |
| 179 | + } | |
| 180 | + | |
| 181 | + /** | |
| 182 | + * 取消下载 删除本地文件 | |
| 183 | + * @param info | |
| 184 | + */ | |
| 185 | + public void cancelDownload(DownloadInfo info){ | |
| 186 | + pauseDownload(info.getUrl()); | |
| 187 | + info.setProgress(0); | |
| 188 | + info.setDownloadStatus(DownloadInfo.DOWNLOAD_CANCEL); | |
| 189 | + EventBus.getDefault().post(info); | |
| 190 | + Constant.deleteFile(info.getFileName()); | |
| 191 | + } | |
| 192 | + | |
| 193 | + /** | |
| 194 | + * 创建DownInfo | |
| 195 | + * | |
| 196 | + * @param url 请求网址 | |
| 197 | + * @return DownInfo | |
| 198 | + */ | |
| 199 | + private DownloadInfo createDownInfo(String url) { | |
| 200 | + DownloadInfo downloadInfo = new DownloadInfo(url); | |
| 201 | + long contentLength = getContentLength(url);//获得文件大小 | |
| 202 | + downloadInfo.setTotal(contentLength); | |
| 203 | + String fileName = url.substring(url.lastIndexOf("/")); | |
| 204 | + downloadInfo.setFileName(fileName); | |
| 205 | + return downloadInfo; | |
| 206 | + } | |
| 207 | + | |
| 208 | + /** | |
| 209 | + * 如果文件已下载重新命名新文件名 | |
| 210 | + * @param downloadInfo | |
| 211 | + * @return | |
| 212 | + */ | |
| 213 | + private DownloadInfo getRealFileName(DownloadInfo downloadInfo) { | |
| 214 | + String fileName = downloadInfo.getFileName(); | |
| 215 | + long downloadLength = 0, contentLength = downloadInfo.getTotal(); | |
| 216 | + File path = new File(Constant.FILE_PATH); | |
| 217 | + if (!path.exists()) { | |
| 218 | + path.mkdir(); | |
| 219 | + } | |
| 220 | + File file = new File(Constant.FILE_PATH, fileName); | |
| 221 | + if (file.exists()) { | |
| 222 | + //找到了文件,代表已经下载过,则获取其长度 | |
| 223 | + downloadLength = file.length(); | |
| 224 | + } | |
| 225 | + //之前下载过,需要重新来一个文件 | |
| 226 | + int i = 1; | |
| 227 | + while (downloadLength >= contentLength) { | |
| 228 | + int dotIndex = fileName.lastIndexOf("."); | |
| 229 | + String fileNameOther; | |
| 230 | + if (dotIndex == -1) { | |
| 231 | + fileNameOther = fileName + "(" + i + ")"; | |
| 232 | + } else { | |
| 233 | + fileNameOther = fileName.substring(0, dotIndex) | |
| 234 | + + "(" + i + ")" + fileName.substring(dotIndex); | |
| 235 | + } | |
| 236 | + File newFile = new File(Constant.FILE_PATH, fileNameOther); | |
| 237 | + file = newFile; | |
| 238 | + downloadLength = newFile.length(); | |
| 239 | + i++; | |
| 240 | + } | |
| 241 | + //设置改变过的文件名/大小 | |
| 242 | + downloadInfo.setProgress(downloadLength); | |
| 243 | + downloadInfo.setFileName(file.getName()); | |
| 244 | + return downloadInfo; | |
| 245 | + } | |
| 246 | + | |
| 247 | + private class DownloadSubscribe implements ObservableOnSubscribe<DownloadInfo> { | |
| 248 | + private DownloadInfo downloadInfo; | |
| 249 | + | |
| 250 | + public DownloadSubscribe(DownloadInfo downloadInfo) { | |
| 251 | + this.downloadInfo = downloadInfo; | |
| 252 | + } | |
| 253 | + | |
| 254 | + @Override | |
| 255 | + public void subscribe(ObservableEmitter<DownloadInfo> e) throws Exception { | |
| 256 | + String url = downloadInfo.getUrl(); | |
| 257 | + long downloadLength = downloadInfo.getProgress();//已经下载好的长度 | |
| 258 | + long contentLength = downloadInfo.getTotal();//文件的总长度 | |
| 259 | + //初始进度信息 | |
| 260 | + e.onNext(downloadInfo); | |
| 261 | + Request request = new Request.Builder() | |
| 262 | + //确定下载的范围,添加此头,则服务器就可以跳过已经下载好的部分 | |
| 263 | + .addHeader("RANGE", "bytes=" + downloadLength + "-" + contentLength) | |
| 264 | + .url(url) | |
| 265 | + .build(); | |
| 266 | + Call call = mClient.newCall(request); | |
| 267 | + downCalls.put(url, call);//把这个添加到call里,方便取消 | |
| 268 | + Response response = call.execute(); | |
| 269 | + File file = new File(Constant.FILE_PATH, downloadInfo.getFileName()); | |
| 270 | + InputStream is = null; | |
| 271 | + FileOutputStream fileOutputStream = null; | |
| 272 | + try { | |
| 273 | + is = response.body().byteStream(); | |
| 274 | + fileOutputStream = new FileOutputStream(file, true); | |
| 275 | + byte[] buffer = new byte[2048];//缓冲数组2kB | |
| 276 | + int len; | |
| 277 | + while ((len = is.read(buffer)) != -1) { | |
| 278 | + fileOutputStream.write(buffer, 0, len); | |
| 279 | + downloadLength += len; | |
| 280 | + downloadInfo.setProgress(downloadLength); | |
| 281 | + e.onNext(downloadInfo); | |
| 282 | + } | |
| 283 | + fileOutputStream.flush(); | |
| 284 | + downCalls.remove(url); | |
| 285 | + } finally { | |
| 286 | + //关闭IO流 | |
| 287 | + DownloadIO.closeAll(is, fileOutputStream); | |
| 288 | + | |
| 289 | + } | |
| 290 | + e.onComplete();//完成 | |
| 291 | + } | |
| 292 | + } | |
| 293 | + | |
| 294 | + /** | |
| 295 | + * 获取下载长度 | |
| 296 | + * | |
| 297 | + * @param downloadUrl | |
| 298 | + * @return | |
| 299 | + */ | |
| 300 | + private long getContentLength(String downloadUrl) { | |
| 301 | + Request request = new Request.Builder() | |
| 302 | + .url(downloadUrl) | |
| 303 | + .build(); | |
| 304 | + try { | |
| 305 | + Response response = mClient.newCall(request).execute(); | |
| 306 | + if (response != null && response.isSuccessful()) { | |
| 307 | + long contentLength = response.body().contentLength(); | |
| 308 | + response.close(); | |
| 309 | + return contentLength == 0 ? DownloadInfo.TOTAL_ERROR : contentLength; | |
| 310 | + } | |
| 311 | + } catch (IOException e) { | |
| 312 | + e.printStackTrace(); | |
| 313 | + } | |
| 314 | + return DownloadInfo.TOTAL_ERROR; | |
| 315 | + } | |
| 316 | + | |
| 317 | +} | |
| 318 | +``` | |
| 319 | +这里要多分析一下,下载管理类是单例模式这是必须的,里面定义一个HashMap用来存放所有的下载任务,里面的download()方法,是主要过程 | |
| 320 | +```Java | |
| 321 | +public void download(String url, DownloadObserver downLoadObserver) { | |
| 322 | + | |
| 323 | + Observable.just(url) | |
| 324 | + .filter(new Predicate<String>() { | |
| 325 | + @Override | |
| 326 | + public boolean test(String s) { | |
| 327 | + return !downCalls.containsKey(s); | |
| 328 | + } | |
| 329 | + }) // 过滤 call的map中已经有了,就证明正在下载,则这次不下载 | |
| 330 | + .flatMap(new Function<String, ObservableSource<?>>() { | |
| 331 | + @Override | |
| 332 | + public ObservableSource<?> apply(String s) { | |
| 333 | + return Observable.just(createDownInfo(s)); | |
| 334 | + } | |
| 335 | + }) // 生成 DownloadInfo | |
| 336 | + .map(new Function<Object, DownloadInfo>() { | |
| 337 | + @Override | |
| 338 | + public DownloadInfo apply(Object o) { | |
| 339 | + return getRealFileName((DownloadInfo)o); | |
| 340 | + } | |
| 341 | + }) // 如果已经下载,重新命名 | |
| 342 | + .flatMap(new Function<DownloadInfo, ObservableSource<DownloadInfo>>() { | |
| 343 | + @Override | |
| 344 | + public ObservableSource<DownloadInfo> apply(DownloadInfo downloadInfo) { | |
| 345 | + return Observable.create(new DownloadSubscribe(downloadInfo)); | |
| 346 | + } | |
| 347 | + }) // 下载 | |
| 348 | + .observeOn(AndroidSchedulers.mainThread()) // 在主线程中回调 | |
| 349 | + .subscribeOn(Schedulers.io()) // 在子线程中执行 | |
| 350 | + .subscribe(downLoadObserver); // 添加观察者,监听下载进度 | |
| 351 | + } | |
| 352 | +``` | |
| 353 | +这里用到的是Rxjava,第一步filter,过滤下载,已经下载的url再点击下载是不会另起下载任务的;第二步flatMap,通过url生成Bean类,这个按需求来设计,也可以直接传一个Bean进来也是可以的;第三步map,如果这个文件已经下载了,再次下载重新命名文件,这也是根据需求改变,如果下载过的文件不需要下载,这就可以省了;第四步flatMap,去下载具体去看下载方法;剩下的就是切换线程和添加观察者了。 | |
| 354 | +### step4 观察者 | |
| 355 | +```Java | |
| 356 | +/** | |
| 357 | + * Created by zs | |
| 358 | + * Date:2018年 09月 12日 | |
| 359 | + * Time:13:50 | |
| 360 | + * ————————————————————————————————————— | |
| 361 | + * About: 观察者 | |
| 362 | + * ————————————————————————————————————— | |
| 363 | + */ | |
| 364 | +public class DownloadObserver implements Observer<DownloadInfo> { | |
| 365 | + | |
| 366 | + public Disposable d;//可以用于取消注册的监听者 | |
| 367 | + public DownloadInfo downloadInfo; | |
| 368 | + | |
| 369 | + @Override | |
| 370 | + public void onSubscribe(Disposable d) { | |
| 371 | + this.d = d; | |
| 372 | + } | |
| 373 | + | |
| 374 | + @Override | |
| 375 | + public void onNext(DownloadInfo value) { | |
| 376 | + this.downloadInfo = value; | |
| 377 | + downloadInfo.setDownloadStatus(DownloadInfo.DOWNLOAD); | |
| 378 | + EventBus.getDefault().post(downloadInfo); | |
| 379 | + } | |
| 380 | + | |
| 381 | + @Override | |
| 382 | + public void onError(Throwable e) { | |
| 383 | + Log.d("My_Log","onError"); | |
| 384 | + if (DownloadManager.getInstance().getDownloadUrl(downloadInfo.getUrl())){ | |
| 385 | + DownloadManager.getInstance().pauseDownload(downloadInfo.getUrl()); | |
| 386 | + downloadInfo.setDownloadStatus(DownloadInfo.DOWNLOAD_ERROR); | |
| 387 | + EventBus.getDefault().post(downloadInfo); | |
| 388 | + }else{ | |
| 389 | + downloadInfo.setDownloadStatus(DownloadInfo.DOWNLOAD_PAUSE); | |
| 390 | + EventBus.getDefault().post(downloadInfo); | |
| 391 | + } | |
| 392 | + | |
| 393 | + } | |
| 394 | + | |
| 395 | + @Override | |
| 396 | + public void onComplete() { | |
| 397 | + Log.d("My_Log","onComplete"); | |
| 398 | + if (downloadInfo != null){ | |
| 399 | + downloadInfo.setDownloadStatus(DownloadInfo.DOWNLOAD_OVER); | |
| 400 | + EventBus.getDefault().post(downloadInfo); | |
| 401 | + } | |
| 402 | + } | |
| 403 | +} | |
| 404 | + | |
| 405 | +``` | |
| 406 | +这里是用到EventBus来通知页面刷新的,当然也可以不用,把订阅者直接写在Activity,但是那样不利于代码的复用,如果多个页面需要进度更新就麻烦了。 | |
| 407 | +### step5 Activity 和 Adapter | |
| 408 | +页面中是一个RecyclerView,交互逻辑不是很多,说一点,Adapter条目的更新,用的notifyItemChanged(i) 每次更新某一条的进度,而不是notifyDataSetChanged()全部刷新,因为调用全部刷新,刷新的频率很高会导致条目中控件的点击事件不好用没有响应,被拦截了,而更新某一条也会有一个问题是条目刷新时会闪动,解决方案是把RecyclerView的刷新动画去掉,这样就解决了。 | |
| 409 | +```Java | |
| 410 | +// 取消item刷新的动画 | |
| 411 | + ((SimpleItemAnimator)recycler_view.getItemAnimator()).setSupportsChangeAnimations(false); | |
| 412 | +``` | |
| 413 | +```Java | |
| 414 | +/** | |
| 415 | + * Created by zs | |
| 416 | + * Date:2018年 09月 11日 | |
| 417 | + * Time:18:06 | |
| 418 | + * ————————————————————————————————————— | |
| 419 | + * About: | |
| 420 | + * ————————————————————————————————————— | |
| 421 | + */ | |
| 422 | +public class DownloadAdapter extends RecyclerView.Adapter<DownloadAdapter.UploadHolder> { | |
| 423 | + | |
| 424 | + private List<DownloadInfo> mdata; | |
| 425 | + | |
| 426 | + public DownloadAdapter(List<DownloadInfo> mdata) { | |
| 427 | + this.mdata = mdata; | |
| 428 | + } | |
| 429 | + | |
| 430 | + /** | |
| 431 | + * 更新下载进度 | |
| 432 | + * @param info | |
| 433 | + */ | |
| 434 | + public void updateProgress(DownloadInfo info){ | |
| 435 | + for (int i = 0; i < mdata.size(); i++){ | |
| 436 | + if (mdata.get(i).getUrl().equals(info.getUrl())){ | |
| 437 | + mdata.set(i,info); | |
| 438 | + notifyItemChanged(i); | |
| 439 | + break; | |
| 440 | + } | |
| 441 | + } | |
| 442 | + } | |
| 443 | + | |
| 444 | + @Override | |
| 445 | + public UploadHolder onCreateViewHolder(ViewGroup parent, int viewType) { | |
| 446 | + View view = View.inflate(parent.getContext(), R.layout.item_download_layout,null); | |
| 447 | + return new UploadHolder(view); | |
| 448 | + } | |
| 449 | + | |
| 450 | + @Override | |
| 451 | + public void onBindViewHolder(UploadHolder holder, int position) { | |
| 452 | + | |
| 453 | + final DownloadInfo info = mdata.get(position); | |
| 454 | + if (DownloadInfo.DOWNLOAD_CANCEL.equals(info.getDownloadStatus())){ | |
| 455 | + holder.main_progress.setProgress(0); | |
| 456 | + }else if (DownloadInfo.DOWNLOAD_OVER.equals(info.getDownloadStatus())){ | |
| 457 | + holder.main_progress.setProgress(holder.main_progress.getMax()); | |
| 458 | + }else { | |
| 459 | + if (info.getTotal() == 0){ | |
| 460 | + holder.main_progress.setProgress(0); | |
| 461 | + }else { | |
| 462 | + float d = info.getProgress() * holder.main_progress.getMax() / info.getTotal(); | |
| 463 | + holder.main_progress.setProgress((int) d); | |
| 464 | + } | |
| 465 | + } | |
| 466 | + holder.main_btn_down.setOnClickListener(new View.OnClickListener() { | |
| 467 | + @Override | |
| 468 | + public void onClick(View view) { | |
| 469 | + DownloadManager.getInstance().download(info.getUrl(), new DownloadObserver()); | |
| 470 | + } | |
| 471 | + }); | |
| 472 | + | |
| 473 | + holder.main_btn_pause.setOnClickListener(new View.OnClickListener() { | |
| 474 | + @Override | |
| 475 | + public void onClick(View view) { | |
| 476 | + DownloadManager.getInstance().pauseDownload(info.getUrl()); | |
| 477 | + } | |
| 478 | + }); | |
| 479 | + | |
| 480 | + holder.main_btn_cancel.setOnClickListener(new View.OnClickListener() { | |
| 481 | + @Override | |
| 482 | + public void onClick(View view) { | |
| 483 | + DownloadManager.getInstance().cancelDownload(info); | |
| 484 | + } | |
| 485 | + }); | |
| 486 | + } | |
| 487 | + | |
| 488 | + @Override | |
| 489 | + public int getItemCount() { | |
| 490 | + return mdata.size(); | |
| 491 | + } | |
| 492 | + | |
| 493 | + public class UploadHolder extends RecyclerView.ViewHolder{ | |
| 494 | + | |
| 495 | + private ProgressBar main_progress; | |
| 496 | + private Button main_btn_down; | |
| 497 | + private Button main_btn_pause; | |
| 498 | + private Button main_btn_cancel; | |
| 499 | + | |
| 500 | + public UploadHolder(View itemView) { | |
| 501 | + super(itemView); | |
| 502 | + main_progress = itemView.findViewById(R.id.main_progress); | |
| 503 | + main_btn_down = itemView.findViewById(R.id.main_btn_down); | |
| 504 | + main_btn_pause = itemView.findViewById(R.id.main_btn_pause); | |
| 505 | + main_btn_cancel = itemView.findViewById(R.id.main_btn_cancel); | |
| 506 | + } | |
| 507 | + } | |
| 508 | + | |
| 509 | +} | |
| 510 | + | |
| 511 | +``` | |
| 512 | +### github地址 | |
| 513 | +https://github.com/QQzs/DownloadFile | |
| 514 | + | |
| 515 | +### 简书地址 | |
| 516 | +https://www.jianshu.com/p/4bab2e9c577e | |
| 517 | + | |
| 518 | +参考地址: | |
| 519 | +https://blog.csdn.net/cfy137000/article/details/54838608 | |
| 520 | +所有内容基本是参考的这篇文章,我只是少有修改,希望给大家有所帮助。 | ... | ... |
app/.gitignore
0 → 100644
app/build.gradle
0 → 100644
| 1 | +++ a/app/build.gradle | |
| 1 | +apply plugin: 'com.android.application' | |
| 2 | +apply plugin: 'org.greenrobot.greendao' // apply plugin | |
| 3 | + | |
| 4 | +android { | |
| 5 | + compileSdkVersion 27 | |
| 6 | + defaultConfig { | |
| 7 | + applicationId "com.cnlive.downloadfile" | |
| 8 | + minSdkVersion 16 | |
| 9 | + targetSdkVersion 27 | |
| 10 | + versionCode 1 | |
| 11 | + versionName "1.0" | |
| 12 | + testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" | |
| 13 | + } | |
| 14 | + buildTypes { | |
| 15 | + release { | |
| 16 | + minifyEnabled false | |
| 17 | + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | |
| 18 | + } | |
| 19 | + } | |
| 20 | + | |
| 21 | + greendao { | |
| 22 | + schemaVersion 1 //数据库版本号 | |
| 23 | + daoPackage 'com.cnlive.downloadfile.database.greenDao.db' | |
| 24 | +// 设置DaoMaster、DaoSession、Dao 包名 | |
| 25 | + targetGenDir 'src/main/java'//设置DaoMaster、DaoSession、Dao目录 | |
| 26 | + generateTests false //设置为true以自动生成单元测试。 | |
| 27 | + targetGenDirTests 'src/main/java' //应存储生成的单元测试的基本目录。默认为 src / androidTest / java。 | |
| 28 | + } | |
| 29 | +} | |
| 30 | + | |
| 31 | +dependencies { | |
| 32 | + implementation fileTree(dir: 'libs', include: ['*.jar']) | |
| 33 | + implementation 'com.android.support:appcompat-v7:27.1.1' | |
| 34 | + implementation 'com.android.support.constraint:constraint-layout:1.1.3' | |
| 35 | + testImplementation 'junit:junit:4.12' | |
| 36 | + androidTestImplementation 'com.android.support.test:runner:1.0.2' | |
| 37 | + androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' | |
| 38 | + | |
| 39 | + // OKHttp RxJava | |
| 40 | + implementation 'com.squareup.okhttp3:okhttp:3.6.0' | |
| 41 | + implementation 'io.reactivex.rxjava2:rxjava:2.1.3' | |
| 42 | + implementation 'io.reactivex.rxjava2:rxandroid:2.0.1' | |
| 43 | + // eventbus | |
| 44 | + implementation 'org.greenrobot:eventbus:3.0.0' | |
| 45 | + implementation 'com.android.support:recyclerview-v7:27.1.1' | |
| 46 | + implementation 'com.google.code.gson:gson:2.8.1' | |
| 47 | + | |
| 48 | + implementation 'org.greenrobot:greendao:3.2.2' | |
| 49 | + | |
| 50 | +} | ... | ... |
app/proguard-rules.pro
0 → 100644
| 1 | +++ a/app/proguard-rules.pro | |
| 1 | +# Add project specific ProGuard rules here. | |
| 2 | +# You can control the set of applied configuration files using the | |
| 3 | +# proguardFiles setting in build.gradle. | |
| 4 | +# | |
| 5 | +# For more details, see | |
| 6 | +# http://developer.android.com/guide/developing/tools/proguard.html | |
| 7 | + | |
| 8 | +# If your project uses WebView with JS, uncomment the following | |
| 9 | +# and specify the fully qualified class name to the JavaScript interface | |
| 10 | +# class: | |
| 11 | +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { | |
| 12 | +# public *; | |
| 13 | +#} | |
| 14 | + | |
| 15 | +# Uncomment this to preserve the line number information for | |
| 16 | +# debugging stack traces. | |
| 17 | +#-keepattributes SourceFile,LineNumberTable | |
| 18 | + | |
| 19 | +# If you keep the line number information, uncomment this to | |
| 20 | +# hide the original source file name. | |
| 21 | +#-renamesourcefileattribute SourceFile | ... | ... |
app/src/androidTest/java/com/cnlive/downloadfile/ExampleInstrumentedTest.java
0 → 100644
| 1 | +++ a/app/src/androidTest/java/com/cnlive/downloadfile/ExampleInstrumentedTest.java | |
| 1 | +package com.cnlive.downloadfile; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.support.test.InstrumentationRegistry; | |
| 5 | +import android.support.test.runner.AndroidJUnit4; | |
| 6 | + | |
| 7 | +import org.junit.Test; | |
| 8 | +import org.junit.runner.RunWith; | |
| 9 | + | |
| 10 | +import static org.junit.Assert.*; | |
| 11 | + | |
| 12 | +/** | |
| 13 | + * Instrumented test, which will execute on an Android device. | |
| 14 | + * | |
| 15 | + * @see <a href="http://d.android.com/tools/testing">Testing documentation</a> | |
| 16 | + */ | |
| 17 | +@RunWith(AndroidJUnit4.class) | |
| 18 | +public class ExampleInstrumentedTest { | |
| 19 | + @Test | |
| 20 | + public void useAppContext() { | |
| 21 | + // Context of the app under test. | |
| 22 | + Context appContext = InstrumentationRegistry.getTargetContext(); | |
| 23 | + | |
| 24 | + assertEquals("com.zs.demo.downloadfile", appContext.getPackageName()); | |
| 25 | + } | |
| 26 | +} | ... | ... |
app/src/main/AndroidManifest.xml
0 → 100644
| 1 | +++ a/app/src/main/AndroidManifest.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<manifest xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + xmlns:tools="http://schemas.android.com/tools" | |
| 4 | + package="com.cnlive.downloadfile"> | |
| 5 | + | |
| 6 | + <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" /> | |
| 7 | + <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | |
| 8 | + <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /> | |
| 9 | + <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" | |
| 10 | + tools:ignore="ProtectedPermissions" /> | |
| 11 | + | |
| 12 | + <uses-permission android:name="android.permission.INTERNET"/> | |
| 13 | + | |
| 14 | + <application | |
| 15 | + android:name=".MyApplication" | |
| 16 | + android:allowBackup="true" | |
| 17 | + android:icon="@mipmap/ic_launcher" | |
| 18 | + android:label="@string/app_name" | |
| 19 | + android:roundIcon="@mipmap/ic_launcher_round" | |
| 20 | + android:supportsRtl="true" | |
| 21 | + android:theme="@style/AppTheme"> | |
| 22 | + <activity android:name=".MainActivity"> | |
| 23 | + <intent-filter> | |
| 24 | + <action android:name="android.intent.action.MAIN" /> | |
| 25 | + | |
| 26 | + <category android:name="android.intent.category.LAUNCHER" /> | |
| 27 | + </intent-filter> | |
| 28 | + </activity> | |
| 29 | + <activity android:name=".LimitActivity"/> | |
| 30 | + <service android:name=".download.limit.DownLoadService"/> | |
| 31 | + </application> | |
| 32 | + | |
| 33 | +</manifest> | |
| 0 | 34 | \ No newline at end of file | ... | ... |
app/src/main/java/com/cnlive/downloadfile/Constant.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/Constant.java | |
| 1 | +package com.cnlive.downloadfile; | |
| 2 | + | |
| 3 | +import android.os.Environment; | |
| 4 | + | |
| 5 | +import java.io.File; | |
| 6 | + | |
| 7 | +/** | |
| 8 | + * Created by zs | |
| 9 | + * Date:2018年 09月 12日 | |
| 10 | + * Time:13:54 | |
| 11 | + * ————————————————————————————————————— | |
| 12 | + * About: | |
| 13 | + * ————————————————————————————————————— | |
| 14 | + */ | |
| 15 | +public class Constant { | |
| 16 | + | |
| 17 | + /** | |
| 18 | + * 下载路径 | |
| 19 | + */ | |
| 20 | + public final static String FILE_PATH = Environment.getExternalStorageDirectory().getAbsolutePath()+"/AAA/"; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * 若文件下载不下来,更换网址 | |
| 24 | + */ | |
| 25 | + public final static String URL_1 = "http://files.ibaodian.com/v2/teamfile/1ca447a600580cdcb575ab9348536f38/CM10086_android_V4.8.0_20180708_A0001.apk"; | |
| 26 | + public final static String URL_2 = "http://files.ibaodian.com/v2/teamfile/f063d3c2c4a32a8143fc4f36be39cfd9/jtyh.patch"; | |
| 27 | + public final static String URL_3 = "http://files.ibaodian.com/v2/teamfile/482fd8d425d25f3c3fbdb83156a85af1/IMG_20160508_184212.jpg"; | |
| 28 | + public final static String URL_4 = "http://files.ibaodian.com/v2/teamfile/c0ab1e924a99738a268c137f60f3a6db/IMG_20160525_115133.jpg"; | |
| 29 | + public final static String URL_5 = "http://files.ibaodian.com/v2/teamfile/5fe13f1385a0112fb75fceed364088e7/IMG_20180818_132629.jpg"; | |
| 30 | + public final static String URL_6 = "http://files.ibaodian.com/v2/teamfile/da43a96fde668d4c3fd6f89b8da7e20c/5b726910e7bce766b218d0ee.jpg"; | |
| 31 | + public final static String URL_7 = "http://files.ibaodian.com/v2/teamfile/ac43a96d0f21e83cd3967e60e6775d1d/sf_updata.apk"; | |
| 32 | + public final static String URL_8 = "http://files.ibaodian.com/v2/teamfile/长城金禧利年金保险菁华版(A计划).pdf"; | |
| 33 | + public final static String URL_9 = "http://files.ibaodian.com/v2/teamfile/2b1d7f518fbcf467ec9bf748743bea80/D90B2EA927372212B33BB673318AA1A1361024EB20B8493A9B23E8178DF3D001"; | |
| 34 | + | |
| 35 | + /** | |
| 36 | + * 删除文件 | |
| 37 | + * | |
| 38 | + * @param fileName | |
| 39 | + * @return | |
| 40 | + */ | |
| 41 | + public static boolean deleteFile(String fileName) { | |
| 42 | + boolean status; | |
| 43 | + SecurityManager checker = new SecurityManager(); | |
| 44 | + File file = new File(FILE_PATH + fileName); | |
| 45 | + if (file.exists()){ | |
| 46 | + checker.checkDelete(file.toString()); | |
| 47 | + if (file.isFile()) { | |
| 48 | + try { | |
| 49 | + file.delete(); | |
| 50 | + status = true; | |
| 51 | + } catch (SecurityException se) { | |
| 52 | + se.printStackTrace(); | |
| 53 | + status = false; | |
| 54 | + } | |
| 55 | + } else | |
| 56 | + status = false; | |
| 57 | + }else | |
| 58 | + status = false; | |
| 59 | + return status; | |
| 60 | + } | |
| 61 | + | |
| 62 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/LimitActivity.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/LimitActivity.java | |
| 1 | +package com.cnlive.downloadfile; | |
| 2 | + | |
| 3 | +import android.content.Intent; | |
| 4 | +import android.os.Bundle; | |
| 5 | +import android.support.annotation.Nullable; | |
| 6 | +import android.support.v7.app.AppCompatActivity; | |
| 7 | +import android.support.v7.widget.LinearLayoutManager; | |
| 8 | +import android.support.v7.widget.RecyclerView; | |
| 9 | +import android.support.v7.widget.SimpleItemAnimator; | |
| 10 | +import android.util.Log; | |
| 11 | +import android.view.View; | |
| 12 | +import android.widget.Button; | |
| 13 | +import android.widget.Toast; | |
| 14 | + | |
| 15 | +import com.cnlive.downloadfile.adapter.LimitDownloadAdapter; | |
| 16 | +import com.cnlive.downloadfile.download.limit.DownLoadService; | |
| 17 | +import com.cnlive.downloadfile.download.limit.DownloadInfo; | |
| 18 | +import com.cnlive.downloadfile.download.limit.DownloadLimitManager; | |
| 19 | +import com.cnlive.downloadfile.download.limit.DownloadStatus; | |
| 20 | +import com.cnlive.downloadfile.download.util.NetWorkUtil; | |
| 21 | + | |
| 22 | +import org.greenrobot.eventbus.EventBus; | |
| 23 | +import org.greenrobot.eventbus.Subscribe; | |
| 24 | +import org.greenrobot.eventbus.ThreadMode; | |
| 25 | + | |
| 26 | +import java.util.ArrayList; | |
| 27 | +import java.util.List; | |
| 28 | + | |
| 29 | +import static com.cnlive.downloadfile.download.util.CheckNetworkStatusChangeListener.Status.TYPE_MOBILE; | |
| 30 | +import static com.cnlive.downloadfile.download.util.CheckNetworkStatusChangeListener.Status.TYPE_UN_NETWORK; | |
| 31 | +import static com.cnlive.downloadfile.download.util.CheckNetworkStatusChangeListener.Status.TYPE_WIFI; | |
| 32 | + | |
| 33 | + | |
| 34 | +public class LimitActivity extends AppCompatActivity implements View.OnClickListener { | |
| 35 | + | |
| 36 | + private RecyclerView recycler_view; | |
| 37 | + private LimitDownloadAdapter mAdapter; | |
| 38 | + private List<DownloadInfo> mData = new ArrayList<>(); | |
| 39 | + private Button allStartPause, allClear; | |
| 40 | + | |
| 41 | + @Override | |
| 42 | + protected void onCreate(@Nullable Bundle savedInstanceState) { | |
| 43 | + super.onCreate(savedInstanceState); | |
| 44 | + setContentView(R.layout.activity_recycler); | |
| 45 | + EventBus.getDefault().register(this); | |
| 46 | + recycler_view = findViewById(R.id.recycler_view); | |
| 47 | + | |
| 48 | + allStartPause = findViewById(R.id.start_pause); | |
| 49 | + allClear = findViewById(R.id.clear); | |
| 50 | + | |
| 51 | + allStartPause.setOnClickListener(this); | |
| 52 | + allClear.setOnClickListener(this); | |
| 53 | + if (DownloadLimitManager.getInstance().getCurremtDownload() == null) { | |
| 54 | + allStartPause.setText("全部开始"); | |
| 55 | + } else { | |
| 56 | + allStartPause.setText("全部暂停"); | |
| 57 | + } | |
| 58 | + mData = MyApplication.getInstances().getDaoSession().loadAll(DownloadInfo.class); | |
| 59 | + mAdapter = new LimitDownloadAdapter(this, mData); | |
| 60 | + recycler_view.setLayoutManager(new LinearLayoutManager(this)); | |
| 61 | + recycler_view.setAdapter(mAdapter); | |
| 62 | + // 取消item刷新的动画 | |
| 63 | + ((SimpleItemAnimator) recycler_view.getItemAnimator()).setSupportsChangeAnimations(false); | |
| 64 | + | |
| 65 | + mAdapter.setDelectClick(new LimitDownloadAdapter.DelectClick() { | |
| 66 | + @Override | |
| 67 | + public void onDelectClickListener(DownloadInfo downloadInfo, int position) { | |
| 68 | + //删除该下载 | |
| 69 | + Intent intent = new Intent(LimitActivity.this, DownLoadService.class); | |
| 70 | + intent.setAction(DownLoadService.ACTION_DELECT); | |
| 71 | + intent.putExtra("fileUrl", downloadInfo); | |
| 72 | + startService(intent); | |
| 73 | + | |
| 74 | + mData.remove(position); | |
| 75 | + mAdapter.notifyItemRemoved(position); | |
| 76 | + mAdapter.notifyDataSetChanged(); | |
| 77 | + } | |
| 78 | + }); | |
| 79 | + } | |
| 80 | + | |
| 81 | + @Subscribe(threadMode = ThreadMode.MAIN) | |
| 82 | + public void update(DownloadInfo info) { | |
| 83 | + if (DownloadStatus.DOWNLOAD.equals(info.getDownloadStatus())) { | |
| 84 | + allStartPause.setText("全部暂停"); | |
| 85 | + Log.e("ssssss", "update: "+"dowing"); | |
| 86 | + mAdapter.updateProgress(info); | |
| 87 | + } else if (DownloadStatus.DOWNLOAD_OVER.equals(info.getDownloadStatus())) { | |
| 88 | + for (int i = 0; i < mData.size(); i++) { | |
| 89 | + if (mData.get(i).getUrl().equals(info.getUrl())) { | |
| 90 | + mData.set(i, info); | |
| 91 | + MyApplication.getInstances().getDaoSession().delete(info); | |
| 92 | + mData.remove(i); | |
| 93 | + mAdapter.notifyItemRemoved(i); | |
| 94 | + mAdapter.notifyDataSetChanged(); | |
| 95 | + break; | |
| 96 | + } | |
| 97 | + } | |
| 98 | + if (DownloadLimitManager.getInstance().getCurremtDownload() == null) { | |
| 99 | + allStartPause.setText("全部开始"); | |
| 100 | + } | |
| 101 | + } else if (DownloadStatus.DOWNLOAD_PAUSE.equals(info.getDownloadStatus())) { | |
| 102 | + mAdapter.updateProgress(info); | |
| 103 | + boolean isAllPause = true; | |
| 104 | + for(int i = 0;i < mData.size();i++){ | |
| 105 | + if(!mData.get(i).getDownloadStatus().equals(DownloadStatus.DOWNLOAD_PAUSE)){ | |
| 106 | + isAllPause = false; | |
| 107 | + break; | |
| 108 | + } | |
| 109 | + } | |
| 110 | + if(isAllPause){ | |
| 111 | + allStartPause.setText("全部开始"); | |
| 112 | + } | |
| 113 | + } else if (DownloadStatus.DOWNLOAD_WAIT.equals(info.getDownloadStatus())) { | |
| 114 | + mAdapter.updateProgress(info); | |
| 115 | + } else if (DownloadStatus.DOWNLOAD_ERROR.equals(info.getDownloadStatus())) { | |
| 116 | + Toast.makeText(this, "下载出错", Toast.LENGTH_SHORT).show(); | |
| 117 | + } | |
| 118 | + } | |
| 119 | + | |
| 120 | + @Override | |
| 121 | + protected void onDestroy() { | |
| 122 | + super.onDestroy(); | |
| 123 | + EventBus.getDefault().unregister(this); | |
| 124 | + } | |
| 125 | + | |
| 126 | + @Override | |
| 127 | + public void onClick(View v) { | |
| 128 | + switch (v.getId()) { | |
| 129 | + case R.id.start_pause: | |
| 130 | + if(NetWorkUtil.getNetworkConnectionType(LimitActivity.this).equals(TYPE_UN_NETWORK)){ | |
| 131 | + Toast.makeText(LimitActivity.this,"无网络",Toast.LENGTH_SHORT).show(); | |
| 132 | + return; | |
| 133 | + } | |
| 134 | + | |
| 135 | + if(NetWorkUtil.getNetworkConnectionType(LimitActivity.this).equals(TYPE_WIFI)){ | |
| 136 | + allPause(); | |
| 137 | + return; | |
| 138 | + } | |
| 139 | + | |
| 140 | + if(NetWorkUtil.getNetworkConnectionType(LimitActivity.this).equals(TYPE_MOBILE)){ | |
| 141 | + //弹框...保存用户习惯,拒绝或者是允许,允许的话是仅允许一次还是都允许 | |
| 142 | + | |
| 143 | + } | |
| 144 | + | |
| 145 | + break; | |
| 146 | + case R.id.clear: | |
| 147 | + Intent intent = new Intent(LimitActivity.this, DownLoadService.class); | |
| 148 | + intent.setAction(DownLoadService.ACION_CLEAR); | |
| 149 | + startService(intent); | |
| 150 | + mData.clear(); | |
| 151 | + mAdapter.notifyDataSetChanged(); | |
| 152 | + break; | |
| 153 | + } | |
| 154 | + } | |
| 155 | + | |
| 156 | + private void allPause(){ | |
| 157 | + if (allStartPause.getText().toString().equals("全部开始")) { | |
| 158 | + allStartPause.setText("全部暂停"); | |
| 159 | + Log.e("ssssss", "update: "+"全部暂停"); | |
| 160 | + Intent intent = new Intent(LimitActivity.this, DownLoadService.class); | |
| 161 | + intent.setAction(DownLoadService.ACTION_ALLSTART); | |
| 162 | + startService(intent); | |
| 163 | + for(int i = 0;i < mData.size();i++){ | |
| 164 | + mData.get(i).setDownloadStatus(DownloadStatus.DOWNLOAD_WAIT); | |
| 165 | + } | |
| 166 | + mAdapter.notifyDataSetChanged(); | |
| 167 | + } else { | |
| 168 | + //全部暂停,先进行暂停,再开始 | |
| 169 | + Log.e("ssssss", "update: "+"全部开始"); | |
| 170 | + Intent intent = new Intent(LimitActivity.this, DownLoadService.class); | |
| 171 | + intent.setAction(DownLoadService.ACTION_ALLPAUSE); | |
| 172 | + startService(intent); | |
| 173 | + for(int i = 0;i < mData.size();i++){ | |
| 174 | + mData.get(i).setDownloadStatus(DownloadStatus.DOWNLOAD_PAUSE); | |
| 175 | + } | |
| 176 | + mAdapter.notifyDataSetChanged(); | |
| 177 | + } | |
| 178 | + } | |
| 179 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/MainActivity.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/MainActivity.java | |
| 1 | +package com.cnlive.downloadfile; | |
| 2 | + | |
| 3 | +import android.content.Intent; | |
| 4 | +import android.os.Bundle; | |
| 5 | +import android.support.v4.app.ActivityCompat; | |
| 6 | +import android.support.v7.app.AppCompatActivity; | |
| 7 | +import android.view.View; | |
| 8 | +import android.widget.Toast; | |
| 9 | + | |
| 10 | +import com.cnlive.downloadfile.download.limit.DownLoadService; | |
| 11 | +import com.cnlive.downloadfile.download.limit.DownloadInfo; | |
| 12 | +import com.cnlive.downloadfile.download.limit.DownloadLimitManager; | |
| 13 | +import com.cnlive.downloadfile.download.limit.DownloadStatus; | |
| 14 | +import com.cnlive.downloadfile.database.greenDao.db.DownloadInfoDao; | |
| 15 | +import com.cnlive.downloadfile.download.util.NetWorkUtil; | |
| 16 | + | |
| 17 | +import static com.cnlive.downloadfile.download.util.CheckNetworkStatusChangeListener.Status.TYPE_MOBILE; | |
| 18 | +import static com.cnlive.downloadfile.download.util.CheckNetworkStatusChangeListener.Status.TYPE_UN_NETWORK; | |
| 19 | +import static com.cnlive.downloadfile.download.util.CheckNetworkStatusChangeListener.Status.TYPE_WIFI; | |
| 20 | + | |
| 21 | + | |
| 22 | +public class MainActivity extends AppCompatActivity { | |
| 23 | + | |
| 24 | +// private ThreadDAO threadDAO; | |
| 25 | + private static final int REQUEST_EXTERNAL_STORAGE = 1; | |
| 26 | + private static String[] PERMISSIONS_STORAGE = {"android.permission.READ_EXTERNAL_STORAGE", "android.permission.WRITE_EXTERNAL_STORAGE"}; | |
| 27 | + | |
| 28 | + @Override | |
| 29 | + protected void onCreate(Bundle savedInstanceState) { | |
| 30 | + super.onCreate(savedInstanceState); | |
| 31 | + setContentView(R.layout.activity_main); | |
| 32 | +// threadDAO = new ThreadDAOImpl(this); | |
| 33 | + ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE); | |
| 34 | + } | |
| 35 | + | |
| 36 | + public void singleDownload(View view) { | |
| 37 | +// Intent intent = new Intent(this,SingleActivity.class); | |
| 38 | +// startActivity(intent); | |
| 39 | + } | |
| 40 | + | |
| 41 | + public void multipleDownload(View view) { | |
| 42 | + if(NetWorkUtil.getNetworkConnectionType(MainActivity.this).equals(TYPE_UN_NETWORK)){ | |
| 43 | + Toast.makeText(MainActivity.this,"无网络",Toast.LENGTH_SHORT).show(); | |
| 44 | + return; | |
| 45 | + } | |
| 46 | + | |
| 47 | + if(NetWorkUtil.getNetworkConnectionType(MainActivity.this).equals(TYPE_WIFI)){ | |
| 48 | + DownloadInfoDao downloadInfoDao = MyApplication.getInstances().getDaoSession().getDownloadInfoDao(); | |
| 49 | + downloadInfoDao.insertOrReplace(new DownloadInfo(5,Constant.URL_6, "", DownloadStatus.DOWNLOAD_WAIT, 0, 0,"")); | |
| 50 | + downloadInfoDao.insertOrReplace(new DownloadInfo(6,Constant.URL_7, "", DownloadStatus.DOWNLOAD_WAIT, 0, 0,"")); | |
| 51 | + downloadInfoDao.insertOrReplace(new DownloadInfo(7,Constant.URL_8, "", DownloadStatus.DOWNLOAD_WAIT, 0, 0,"")); | |
| 52 | + downloadInfoDao.insertOrReplace(new DownloadInfo(8,Constant.URL_9, "", DownloadStatus.DOWNLOAD_WAIT, 0, 0,"")); | |
| 53 | + if(DownloadLimitManager.getInstance().getCurremtDownload() == null){ | |
| 54 | + DownloadInfo downloadInfo = new DownloadInfo(5,Constant.URL_6, "", DownloadStatus.DOWNLOAD, 0, 0,""); | |
| 55 | + Intent intent = new Intent(this, DownLoadService.class); | |
| 56 | + intent.setAction(DownLoadService.ACTION_START); | |
| 57 | + intent.putExtra("fileUrl", downloadInfo); | |
| 58 | + startService(intent); | |
| 59 | + } | |
| 60 | + return; | |
| 61 | + } | |
| 62 | + | |
| 63 | + if(NetWorkUtil.getNetworkConnectionType(MainActivity.this).equals(TYPE_MOBILE)){ | |
| 64 | + //弹框...保存用户习惯,拒绝或者是允许,允许的话是仅允许一次还是都允许 | |
| 65 | + | |
| 66 | + } | |
| 67 | + } | |
| 68 | + | |
| 69 | + public void addDownload(View view){ | |
| 70 | + if(NetWorkUtil.getNetworkConnectionType(MainActivity.this).equals(TYPE_UN_NETWORK)){ | |
| 71 | + Toast.makeText(MainActivity.this,"无网络",Toast.LENGTH_SHORT).show(); | |
| 72 | + return; | |
| 73 | + } | |
| 74 | + | |
| 75 | + if(NetWorkUtil.getNetworkConnectionType(MainActivity.this).equals(TYPE_WIFI)){ | |
| 76 | + initData(); | |
| 77 | + return; | |
| 78 | + } | |
| 79 | + | |
| 80 | + if(NetWorkUtil.getNetworkConnectionType(MainActivity.this).equals(TYPE_MOBILE)){ | |
| 81 | + //弹框...保存用户习惯,拒绝或者是允许,允许的话是仅允许一次还是都允许 | |
| 82 | + | |
| 83 | + } | |
| 84 | + } | |
| 85 | + | |
| 86 | + private void initData() { | |
| 87 | + DownloadInfoDao downloadInfoDao = MyApplication.getInstances().getDaoSession().getDownloadInfoDao(); | |
| 88 | + downloadInfoDao.insertOrReplace(new DownloadInfo(0,Constant.URL_1, "", DownloadStatus.DOWNLOAD_WAIT, 0, 0,"")); | |
| 89 | + downloadInfoDao.insertOrReplace(new DownloadInfo(1,Constant.URL_2, "", DownloadStatus.DOWNLOAD_WAIT, 0, 0,"")); | |
| 90 | + downloadInfoDao.insertOrReplace(new DownloadInfo(2,Constant.URL_3, "", DownloadStatus.DOWNLOAD_WAIT, 0, 0,"")); | |
| 91 | + downloadInfoDao.insertOrReplace(new DownloadInfo(3,Constant.URL_4, "", DownloadStatus.DOWNLOAD_WAIT, 0, 0,"")); | |
| 92 | + downloadInfoDao.insertOrReplace(new DownloadInfo(4,Constant.URL_5, "", DownloadStatus.DOWNLOAD_WAIT, 0, 0,"")); | |
| 93 | + if(DownloadLimitManager.getInstance().getCurremtDownload() == null){ | |
| 94 | + DownloadInfo downloadInfo = new DownloadInfo(0,Constant.URL_1, "", DownloadStatus.DOWNLOAD, 0, 0,""); | |
| 95 | + Intent intent = new Intent(this, DownLoadService.class); | |
| 96 | + intent.setAction(DownLoadService.ACTION_START); | |
| 97 | + intent.putExtra("fileUrl", downloadInfo); | |
| 98 | + startService(intent); | |
| 99 | + } | |
| 100 | + } | |
| 101 | + | |
| 102 | + public void limitDownload(View view) { | |
| 103 | + Intent intent = new Intent(this, LimitActivity.class); | |
| 104 | + startActivity(intent); | |
| 105 | + } | |
| 106 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/MyApplication.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/MyApplication.java | |
| 1 | +package com.cnlive.downloadfile; | |
| 2 | + | |
| 3 | +import android.app.Application; | |
| 4 | +import android.database.sqlite.SQLiteDatabase; | |
| 5 | + | |
| 6 | +import com.cnlive.downloadfile.database.greenDao.db.DaoMaster; | |
| 7 | +import com.cnlive.downloadfile.database.greenDao.db.DaoSession; | |
| 8 | + | |
| 9 | +public class MyApplication extends Application { | |
| 10 | + | |
| 11 | + private static MyApplication application; | |
| 12 | + | |
| 13 | + @Override | |
| 14 | + public void onCreate() { | |
| 15 | + super.onCreate(); | |
| 16 | + application = this; | |
| 17 | + initGreenDao(); | |
| 18 | + } | |
| 19 | + | |
| 20 | + public static MyApplication getInstances() { | |
| 21 | + return application; | |
| 22 | + } | |
| 23 | + | |
| 24 | + | |
| 25 | + /** | |
| 26 | + * 初始化GreenDao,直接在Application中进行初始化操作 | |
| 27 | + */ | |
| 28 | + private void initGreenDao() { | |
| 29 | + DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "aserbao.db"); | |
| 30 | + SQLiteDatabase db = helper.getWritableDatabase(); | |
| 31 | + DaoMaster daoMaster = new DaoMaster(db); | |
| 32 | + daoSession = daoMaster.newSession(); | |
| 33 | + } | |
| 34 | + | |
| 35 | + private DaoSession daoSession; | |
| 36 | + public DaoSession getDaoSession() { | |
| 37 | + return daoSession; | |
| 38 | + } | |
| 39 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/adapter/LimitDownloadAdapter.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/adapter/LimitDownloadAdapter.java | |
| 1 | +package com.cnlive.downloadfile.adapter; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.content.Intent; | |
| 5 | +import android.support.v7.widget.RecyclerView; | |
| 6 | +import android.view.View; | |
| 7 | +import android.view.ViewGroup; | |
| 8 | +import android.widget.Button; | |
| 9 | +import android.widget.ProgressBar; | |
| 10 | +import android.widget.TextView; | |
| 11 | + | |
| 12 | +import com.cnlive.downloadfile.R; | |
| 13 | +import com.cnlive.downloadfile.download.limit.DownLoadService; | |
| 14 | +import com.cnlive.downloadfile.download.limit.DownloadInfo; | |
| 15 | +import com.cnlive.downloadfile.download.limit.DownloadStatus; | |
| 16 | + | |
| 17 | +import java.util.List; | |
| 18 | + | |
| 19 | +public class LimitDownloadAdapter extends RecyclerView.Adapter<LimitDownloadAdapter.UploadHolder> { | |
| 20 | + | |
| 21 | + private Context mContext; | |
| 22 | + private List<DownloadInfo> mdata; | |
| 23 | + private DelectClick delectClick; | |
| 24 | + | |
| 25 | + | |
| 26 | + public DelectClick getDelectClick() { | |
| 27 | + return delectClick; | |
| 28 | + } | |
| 29 | + | |
| 30 | + public void setDelectClick(DelectClick delectClick) { | |
| 31 | + this.delectClick = delectClick; | |
| 32 | + } | |
| 33 | + | |
| 34 | + public LimitDownloadAdapter(Context context , List<DownloadInfo> mdata) { | |
| 35 | + this.mContext = context; | |
| 36 | + this.mdata = mdata; | |
| 37 | + } | |
| 38 | + | |
| 39 | + /** | |
| 40 | + * 更新下载进度 | |
| 41 | + * @param info | |
| 42 | + */ | |
| 43 | + public void updateProgress(DownloadInfo info){ | |
| 44 | + for (int i = 0; i < mdata.size(); i++){ | |
| 45 | + if (mdata.get(i).getUrl().equals(info.getUrl())){ | |
| 46 | + mdata.set(i,info); | |
| 47 | + notifyItemChanged(i); | |
| 48 | + break; | |
| 49 | + } | |
| 50 | + } | |
| 51 | + } | |
| 52 | + | |
| 53 | + @Override | |
| 54 | + public UploadHolder onCreateViewHolder(ViewGroup parent, int viewType) { | |
| 55 | + View view = View.inflate(parent.getContext(), R.layout.item_download_layout,null); | |
| 56 | + return new UploadHolder(view); | |
| 57 | + } | |
| 58 | + | |
| 59 | + @Override | |
| 60 | + public void onBindViewHolder(final UploadHolder holder, final int position) { | |
| 61 | + | |
| 62 | + final DownloadInfo info = mdata.get(position); | |
| 63 | + holder.name.setText(info.getUrl().substring(info.getUrl().length()-5,info.getUrl().length())); | |
| 64 | + if (DownloadStatus.DOWNLOAD_WAIT.equals(info.getDownloadStatus())){ | |
| 65 | + holder.main_btn_down.setText("待下载"); | |
| 66 | + }else if (DownloadStatus.DOWNLOAD_PAUSE.equals(info.getDownloadStatus())){ | |
| 67 | + holder.main_btn_down.setText("已暂停"); | |
| 68 | + } | |
| 69 | + | |
| 70 | + if (info.getTotal() == 0){ | |
| 71 | + holder.main_progress.setProgress(0); | |
| 72 | + }else { | |
| 73 | + float d = info.getProgress() * holder.main_progress.getMax() / info.getTotal(); | |
| 74 | + holder.main_progress.setProgress((int) d); | |
| 75 | + if(DownloadStatus.DOWNLOAD.equals(info.getDownloadStatus())) holder.main_btn_down.setText("下载中"); | |
| 76 | + } | |
| 77 | + holder.main_btn_down.setOnClickListener(new View.OnClickListener() { | |
| 78 | + @Override | |
| 79 | + public void onClick(View view) { | |
| 80 | + if(holder.main_btn_down.getText().toString().equals("下载中")){//暂停 | |
| 81 | + Intent intent = new Intent(mContext, DownLoadService.class); | |
| 82 | + intent.setAction(DownLoadService.ACTION_PAUSE); | |
| 83 | + intent.putExtra("fileUrl", info); | |
| 84 | + mContext.startService(intent); | |
| 85 | + }else if(holder.main_btn_down.getText().toString().equals("已暂停")){ | |
| 86 | + Intent intent = new Intent(mContext, DownLoadService.class); | |
| 87 | + intent.setAction(DownLoadService.ACTION_WAITING); | |
| 88 | + intent.putExtra("fileUrl", info); | |
| 89 | + mContext.startService(intent); | |
| 90 | + }else { | |
| 91 | + Intent intent = new Intent(mContext, DownLoadService.class); | |
| 92 | + intent.setAction(DownLoadService.ACTION_START); | |
| 93 | + intent.putExtra("fileUrl", info); | |
| 94 | + mContext.startService(intent); | |
| 95 | + } | |
| 96 | + } | |
| 97 | + }); | |
| 98 | + | |
| 99 | + holder.main_btn_cancel.setOnClickListener(new View.OnClickListener() { | |
| 100 | + @Override | |
| 101 | + public void onClick(View view) { | |
| 102 | + if(delectClick != null){ | |
| 103 | + delectClick.onDelectClickListener(info,position); | |
| 104 | + } | |
| 105 | + } | |
| 106 | + }); | |
| 107 | + } | |
| 108 | + | |
| 109 | + @Override | |
| 110 | + public int getItemCount() { | |
| 111 | + return mdata.size(); | |
| 112 | + } | |
| 113 | + | |
| 114 | + public class UploadHolder extends RecyclerView.ViewHolder{ | |
| 115 | + | |
| 116 | + private ProgressBar main_progress; | |
| 117 | + private Button main_btn_down; | |
| 118 | + private TextView name; | |
| 119 | + private Button main_btn_cancel; | |
| 120 | + | |
| 121 | + public UploadHolder(View itemView) { | |
| 122 | + super(itemView); | |
| 123 | + main_progress = itemView.findViewById(R.id.main_progress); | |
| 124 | + main_btn_down = itemView.findViewById(R.id.main_btn_down); | |
| 125 | + name = itemView.findViewById(R.id.name); | |
| 126 | + main_btn_cancel = itemView.findViewById(R.id.main_btn_cancel); | |
| 127 | + } | |
| 128 | + } | |
| 129 | + | |
| 130 | + public interface DelectClick{ | |
| 131 | + void onDelectClickListener(DownloadInfo downloadInfo,int position); | |
| 132 | + } | |
| 133 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/database/greenDao/db/DaoMaster.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/database/greenDao/db/DaoMaster.java | |
| 1 | +package com.cnlive.downloadfile.database.greenDao.db; | |
| 2 | + | |
| 3 | +import android.content.Context; | |
| 4 | +import android.database.sqlite.SQLiteDatabase; | |
| 5 | +import android.database.sqlite.SQLiteDatabase.CursorFactory; | |
| 6 | +import android.util.Log; | |
| 7 | + | |
| 8 | +import org.greenrobot.greendao.AbstractDaoMaster; | |
| 9 | +import org.greenrobot.greendao.database.StandardDatabase; | |
| 10 | +import org.greenrobot.greendao.database.Database; | |
| 11 | +import org.greenrobot.greendao.database.DatabaseOpenHelper; | |
| 12 | +import org.greenrobot.greendao.identityscope.IdentityScopeType; | |
| 13 | + | |
| 14 | + | |
| 15 | +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. | |
| 16 | +/** | |
| 17 | + * Master of DAO (schema version 1): knows all DAOs. | |
| 18 | + */ | |
| 19 | +public class DaoMaster extends AbstractDaoMaster { | |
| 20 | + public static final int SCHEMA_VERSION = 1; | |
| 21 | + | |
| 22 | + /** Creates underlying database table using DAOs. */ | |
| 23 | + public static void createAllTables(Database db, boolean ifNotExists) { | |
| 24 | + DownloadInfoDao.createTable(db, ifNotExists); | |
| 25 | + } | |
| 26 | + | |
| 27 | + /** Drops underlying database table using DAOs. */ | |
| 28 | + public static void dropAllTables(Database db, boolean ifExists) { | |
| 29 | + DownloadInfoDao.dropTable(db, ifExists); | |
| 30 | + } | |
| 31 | + | |
| 32 | + /** | |
| 33 | + * WARNING: Drops all table on Upgrade! Use only during development. | |
| 34 | + * Convenience method using a {@link DevOpenHelper}. | |
| 35 | + */ | |
| 36 | + public static DaoSession newDevSession(Context context, String name) { | |
| 37 | + Database db = new DevOpenHelper(context, name).getWritableDb(); | |
| 38 | + DaoMaster daoMaster = new DaoMaster(db); | |
| 39 | + return daoMaster.newSession(); | |
| 40 | + } | |
| 41 | + | |
| 42 | + public DaoMaster(SQLiteDatabase db) { | |
| 43 | + this(new StandardDatabase(db)); | |
| 44 | + } | |
| 45 | + | |
| 46 | + public DaoMaster(Database db) { | |
| 47 | + super(db, SCHEMA_VERSION); | |
| 48 | + registerDaoClass(DownloadInfoDao.class); | |
| 49 | + } | |
| 50 | + | |
| 51 | + public DaoSession newSession() { | |
| 52 | + return new DaoSession(db, IdentityScopeType.Session, daoConfigMap); | |
| 53 | + } | |
| 54 | + | |
| 55 | + public DaoSession newSession(IdentityScopeType type) { | |
| 56 | + return new DaoSession(db, type, daoConfigMap); | |
| 57 | + } | |
| 58 | + | |
| 59 | + /** | |
| 60 | + * Calls {@link #createAllTables(Database, boolean)} in {@link #onCreate(Database)} - | |
| 61 | + */ | |
| 62 | + public static abstract class OpenHelper extends DatabaseOpenHelper { | |
| 63 | + public OpenHelper(Context context, String name) { | |
| 64 | + super(context, name, SCHEMA_VERSION); | |
| 65 | + } | |
| 66 | + | |
| 67 | + public OpenHelper(Context context, String name, CursorFactory factory) { | |
| 68 | + super(context, name, factory, SCHEMA_VERSION); | |
| 69 | + } | |
| 70 | + | |
| 71 | + @Override | |
| 72 | + public void onCreate(Database db) { | |
| 73 | + Log.i("greenDAO", "Creating tables for schema version " + SCHEMA_VERSION); | |
| 74 | + createAllTables(db, false); | |
| 75 | + } | |
| 76 | + } | |
| 77 | + | |
| 78 | + /** WARNING: Drops all table on Upgrade! Use only during development. */ | |
| 79 | + public static class DevOpenHelper extends OpenHelper { | |
| 80 | + public DevOpenHelper(Context context, String name) { | |
| 81 | + super(context, name); | |
| 82 | + } | |
| 83 | + | |
| 84 | + public DevOpenHelper(Context context, String name, CursorFactory factory) { | |
| 85 | + super(context, name, factory); | |
| 86 | + } | |
| 87 | + | |
| 88 | + @Override | |
| 89 | + public void onUpgrade(Database db, int oldVersion, int newVersion) { | |
| 90 | + Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables"); | |
| 91 | + dropAllTables(db, true); | |
| 92 | + onCreate(db); | |
| 93 | + } | |
| 94 | + } | |
| 95 | + | |
| 96 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/database/greenDao/db/DaoSession.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/database/greenDao/db/DaoSession.java | |
| 1 | +package com.cnlive.downloadfile.database.greenDao.db; | |
| 2 | + | |
| 3 | +import java.util.Map; | |
| 4 | + | |
| 5 | +import org.greenrobot.greendao.AbstractDao; | |
| 6 | +import org.greenrobot.greendao.AbstractDaoSession; | |
| 7 | +import org.greenrobot.greendao.database.Database; | |
| 8 | +import org.greenrobot.greendao.identityscope.IdentityScopeType; | |
| 9 | +import org.greenrobot.greendao.internal.DaoConfig; | |
| 10 | + | |
| 11 | +import com.cnlive.downloadfile.download.limit.DownloadInfo; | |
| 12 | + | |
| 13 | +import com.cnlive.downloadfile.database.greenDao.db.DownloadInfoDao; | |
| 14 | + | |
| 15 | +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. | |
| 16 | + | |
| 17 | +/** | |
| 18 | + * {@inheritDoc} | |
| 19 | + * | |
| 20 | + * @see org.greenrobot.greendao.AbstractDaoSession | |
| 21 | + */ | |
| 22 | +public class DaoSession extends AbstractDaoSession { | |
| 23 | + | |
| 24 | + private final DaoConfig downloadInfoDaoConfig; | |
| 25 | + | |
| 26 | + private final DownloadInfoDao downloadInfoDao; | |
| 27 | + | |
| 28 | + public DaoSession(Database db, IdentityScopeType type, Map<Class<? extends AbstractDao<?, ?>>, DaoConfig> | |
| 29 | + daoConfigMap) { | |
| 30 | + super(db); | |
| 31 | + | |
| 32 | + downloadInfoDaoConfig = daoConfigMap.get(DownloadInfoDao.class).clone(); | |
| 33 | + downloadInfoDaoConfig.initIdentityScope(type); | |
| 34 | + | |
| 35 | + downloadInfoDao = new DownloadInfoDao(downloadInfoDaoConfig, this); | |
| 36 | + | |
| 37 | + registerDao(DownloadInfo.class, downloadInfoDao); | |
| 38 | + } | |
| 39 | + | |
| 40 | + public void clear() { | |
| 41 | + downloadInfoDaoConfig.clearIdentityScope(); | |
| 42 | + } | |
| 43 | + | |
| 44 | + public DownloadInfoDao getDownloadInfoDao() { | |
| 45 | + return downloadInfoDao; | |
| 46 | + } | |
| 47 | + | |
| 48 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/database/greenDao/db/DownloadInfoDao.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/database/greenDao/db/DownloadInfoDao.java | |
| 1 | +package com.cnlive.downloadfile.database.greenDao.db; | |
| 2 | + | |
| 3 | +import android.database.Cursor; | |
| 4 | +import android.database.sqlite.SQLiteStatement; | |
| 5 | + | |
| 6 | +import org.greenrobot.greendao.AbstractDao; | |
| 7 | +import org.greenrobot.greendao.Property; | |
| 8 | +import org.greenrobot.greendao.internal.DaoConfig; | |
| 9 | +import org.greenrobot.greendao.database.Database; | |
| 10 | +import org.greenrobot.greendao.database.DatabaseStatement; | |
| 11 | + | |
| 12 | +import com.cnlive.downloadfile.download.limit.DownloadInfo; | |
| 13 | + | |
| 14 | +// THIS CODE IS GENERATED BY greenDAO, DO NOT EDIT. | |
| 15 | +/** | |
| 16 | + * DAO for table "DOWNLOAD_INFO". | |
| 17 | +*/ | |
| 18 | +public class DownloadInfoDao extends AbstractDao<DownloadInfo, Long> { | |
| 19 | + | |
| 20 | + public static final String TABLENAME = "DOWNLOAD_INFO"; | |
| 21 | + | |
| 22 | + /** | |
| 23 | + * Properties of entity DownloadInfo.<br/> | |
| 24 | + * Can be used for QueryBuilder and for referencing column names. | |
| 25 | + */ | |
| 26 | + public static class Properties { | |
| 27 | + public final static Property Id = new Property(0, long.class, "id", true, "_id"); | |
| 28 | + public final static Property Url = new Property(1, String.class, "url", false, "URL"); | |
| 29 | + public final static Property FileName = new Property(2, String.class, "fileName", false, "FILE_NAME"); | |
| 30 | + public final static Property DownloadStatus = new Property(3, String.class, "downloadStatus", false, "DOWNLOAD_STATUS"); | |
| 31 | + public final static Property Total = new Property(4, long.class, "total", false, "TOTAL"); | |
| 32 | + public final static Property Progress = new Property(5, long.class, "progress", false, "PROGRESS"); | |
| 33 | + public final static Property Title = new Property(6, String.class, "title", false, "TITLE"); | |
| 34 | + } | |
| 35 | + | |
| 36 | + | |
| 37 | + public DownloadInfoDao(DaoConfig config) { | |
| 38 | + super(config); | |
| 39 | + } | |
| 40 | + | |
| 41 | + public DownloadInfoDao(DaoConfig config, DaoSession daoSession) { | |
| 42 | + super(config, daoSession); | |
| 43 | + } | |
| 44 | + | |
| 45 | + /** Creates the underlying database table. */ | |
| 46 | + public static void createTable(Database db, boolean ifNotExists) { | |
| 47 | + String constraint = ifNotExists? "IF NOT EXISTS ": ""; | |
| 48 | + db.execSQL("CREATE TABLE " + constraint + "\"DOWNLOAD_INFO\" (" + // | |
| 49 | + "\"_id\" INTEGER PRIMARY KEY NOT NULL ," + // 0: id | |
| 50 | + "\"URL\" TEXT UNIQUE ," + // 1: url | |
| 51 | + "\"FILE_NAME\" TEXT," + // 2: fileName | |
| 52 | + "\"DOWNLOAD_STATUS\" TEXT," + // 3: downloadStatus | |
| 53 | + "\"TOTAL\" INTEGER NOT NULL ," + // 4: total | |
| 54 | + "\"PROGRESS\" INTEGER NOT NULL ," + // 5: progress | |
| 55 | + "\"TITLE\" TEXT);"); // 6: title | |
| 56 | + } | |
| 57 | + | |
| 58 | + /** Drops the underlying database table. */ | |
| 59 | + public static void dropTable(Database db, boolean ifExists) { | |
| 60 | + String sql = "DROP TABLE " + (ifExists ? "IF EXISTS " : "") + "\"DOWNLOAD_INFO\""; | |
| 61 | + db.execSQL(sql); | |
| 62 | + } | |
| 63 | + | |
| 64 | + @Override | |
| 65 | + protected final void bindValues(DatabaseStatement stmt, DownloadInfo entity) { | |
| 66 | + stmt.clearBindings(); | |
| 67 | + stmt.bindLong(1, entity.getId()); | |
| 68 | + | |
| 69 | + String url = entity.getUrl(); | |
| 70 | + if (url != null) { | |
| 71 | + stmt.bindString(2, url); | |
| 72 | + } | |
| 73 | + | |
| 74 | + String fileName = entity.getFileName(); | |
| 75 | + if (fileName != null) { | |
| 76 | + stmt.bindString(3, fileName); | |
| 77 | + } | |
| 78 | + | |
| 79 | + String downloadStatus = entity.getDownloadStatus(); | |
| 80 | + if (downloadStatus != null) { | |
| 81 | + stmt.bindString(4, downloadStatus); | |
| 82 | + } | |
| 83 | + stmt.bindLong(5, entity.getTotal()); | |
| 84 | + stmt.bindLong(6, entity.getProgress()); | |
| 85 | + | |
| 86 | + String title = entity.getTitle(); | |
| 87 | + if (title != null) { | |
| 88 | + stmt.bindString(7, title); | |
| 89 | + } | |
| 90 | + } | |
| 91 | + | |
| 92 | + @Override | |
| 93 | + protected final void bindValues(SQLiteStatement stmt, DownloadInfo entity) { | |
| 94 | + stmt.clearBindings(); | |
| 95 | + stmt.bindLong(1, entity.getId()); | |
| 96 | + | |
| 97 | + String url = entity.getUrl(); | |
| 98 | + if (url != null) { | |
| 99 | + stmt.bindString(2, url); | |
| 100 | + } | |
| 101 | + | |
| 102 | + String fileName = entity.getFileName(); | |
| 103 | + if (fileName != null) { | |
| 104 | + stmt.bindString(3, fileName); | |
| 105 | + } | |
| 106 | + | |
| 107 | + String downloadStatus = entity.getDownloadStatus(); | |
| 108 | + if (downloadStatus != null) { | |
| 109 | + stmt.bindString(4, downloadStatus); | |
| 110 | + } | |
| 111 | + stmt.bindLong(5, entity.getTotal()); | |
| 112 | + stmt.bindLong(6, entity.getProgress()); | |
| 113 | + | |
| 114 | + String title = entity.getTitle(); | |
| 115 | + if (title != null) { | |
| 116 | + stmt.bindString(7, title); | |
| 117 | + } | |
| 118 | + } | |
| 119 | + | |
| 120 | + @Override | |
| 121 | + public Long readKey(Cursor cursor, int offset) { | |
| 122 | + return cursor.getLong(offset + 0); | |
| 123 | + } | |
| 124 | + | |
| 125 | + @Override | |
| 126 | + public DownloadInfo readEntity(Cursor cursor, int offset) { | |
| 127 | + DownloadInfo entity = new DownloadInfo( // | |
| 128 | + cursor.getLong(offset + 0), // id | |
| 129 | + cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1), // url | |
| 130 | + cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2), // fileName | |
| 131 | + cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3), // downloadStatus | |
| 132 | + cursor.getLong(offset + 4), // total | |
| 133 | + cursor.getLong(offset + 5), // progress | |
| 134 | + cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6) // title | |
| 135 | + ); | |
| 136 | + return entity; | |
| 137 | + } | |
| 138 | + | |
| 139 | + @Override | |
| 140 | + public void readEntity(Cursor cursor, DownloadInfo entity, int offset) { | |
| 141 | + entity.setId(cursor.getLong(offset + 0)); | |
| 142 | + entity.setUrl(cursor.isNull(offset + 1) ? null : cursor.getString(offset + 1)); | |
| 143 | + entity.setFileName(cursor.isNull(offset + 2) ? null : cursor.getString(offset + 2)); | |
| 144 | + entity.setDownloadStatus(cursor.isNull(offset + 3) ? null : cursor.getString(offset + 3)); | |
| 145 | + entity.setTotal(cursor.getLong(offset + 4)); | |
| 146 | + entity.setProgress(cursor.getLong(offset + 5)); | |
| 147 | + entity.setTitle(cursor.isNull(offset + 6) ? null : cursor.getString(offset + 6)); | |
| 148 | + } | |
| 149 | + | |
| 150 | + @Override | |
| 151 | + protected final Long updateKeyAfterInsert(DownloadInfo entity, long rowId) { | |
| 152 | + entity.setId(rowId); | |
| 153 | + return rowId; | |
| 154 | + } | |
| 155 | + | |
| 156 | + @Override | |
| 157 | + public Long getKey(DownloadInfo entity) { | |
| 158 | + if(entity != null) { | |
| 159 | + return entity.getId(); | |
| 160 | + } else { | |
| 161 | + return null; | |
| 162 | + } | |
| 163 | + } | |
| 164 | + | |
| 165 | + @Override | |
| 166 | + public boolean hasKey(DownloadInfo entity) { | |
| 167 | + throw new UnsupportedOperationException("Unsupported for entities with a non-null key"); | |
| 168 | + } | |
| 169 | + | |
| 170 | + @Override | |
| 171 | + protected final boolean isEntityUpdateable() { | |
| 172 | + return true; | |
| 173 | + } | |
| 174 | + | |
| 175 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/download/limit/DownLoadService.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/download/limit/DownLoadService.java | |
| 1 | +package com.cnlive.downloadfile.download.limit; | |
| 2 | + | |
| 3 | +import android.annotation.SuppressLint; | |
| 4 | +import android.app.Service; | |
| 5 | +import android.content.BroadcastReceiver; | |
| 6 | +import android.content.Context; | |
| 7 | +import android.content.Intent; | |
| 8 | +import android.content.IntentFilter; | |
| 9 | +import android.net.ConnectivityManager; | |
| 10 | +import android.net.NetworkInfo; | |
| 11 | +import android.os.Handler; | |
| 12 | +import android.os.IBinder; | |
| 13 | +import android.os.Message; | |
| 14 | + | |
| 15 | +/** | |
| 16 | + * 下载服务 | |
| 17 | + */ | |
| 18 | +public class DownLoadService extends Service { | |
| 19 | + private NetConnectionReceiver netConnectionReceiver; | |
| 20 | + private DownloadInfo info = null; | |
| 21 | + public static final String ACTION_START = "ACTION_START"; | |
| 22 | + public static final String ACTION_WAITING = "ACTION_WAITING"; | |
| 23 | + public static final String ACTION_PAUSE = "ACTION_PAUSE"; | |
| 24 | + public static final String ACTION_ALLPAUSE = "ACTION_ALLPAUSE"; | |
| 25 | + public static final String ACTION_ALLSTART = "ACTION_ALLSTRAT"; | |
| 26 | + public static final String ACTION_DELECT = "ACTION_DELECT"; | |
| 27 | + public static final String ACION_CLEAR = "ACION_CLEAR"; | |
| 28 | + | |
| 29 | + @Override | |
| 30 | + public int onStartCommand(Intent intent, int flags, int startId) { | |
| 31 | + //判断Intent的值,获得Activity传来的参数 | |
| 32 | + if(intent != null){ | |
| 33 | + info = (DownloadInfo) intent.getSerializableExtra("fileUrl"); | |
| 34 | + }else { | |
| 35 | + return super.onStartCommand(intent, flags, startId); | |
| 36 | + } | |
| 37 | + if (intent != null && intent.getAction().equals(ACTION_START)) { | |
| 38 | + //启动初始化线程 | |
| 39 | + new MyThread(info).start(); | |
| 40 | + }else if(intent != null && intent.getAction().equals(ACTION_PAUSE)){ | |
| 41 | + //暂停 | |
| 42 | + mHandle.obtainMessage(1, info).sendToTarget(); | |
| 43 | + }else if(intent != null && intent.getAction().equals(ACTION_ALLPAUSE)){ | |
| 44 | + //全部暂停 | |
| 45 | + mHandle.obtainMessage(2).sendToTarget(); | |
| 46 | + }else if(intent != null && intent.getAction().equals(ACTION_ALLSTART)){ | |
| 47 | + //全部开始 | |
| 48 | + mHandle.obtainMessage(3).sendToTarget(); | |
| 49 | + }else if(intent != null && intent.getAction().equals(ACTION_DELECT)){ | |
| 50 | + //取消 | |
| 51 | + mHandle.obtainMessage(4, info).sendToTarget(); | |
| 52 | + }else if(intent != null && intent.getAction().equals(ACION_CLEAR)){ | |
| 53 | + //清空 | |
| 54 | + mHandle.obtainMessage(5).sendToTarget(); | |
| 55 | + }else if(intent != null && intent.getAction().equals(ACTION_WAITING)){ | |
| 56 | + mHandle.obtainMessage(6,info).sendToTarget(); | |
| 57 | + } | |
| 58 | + return super.onStartCommand(intent, flags, startId); | |
| 59 | + } | |
| 60 | + | |
| 61 | + @Override | |
| 62 | + public void onCreate() { | |
| 63 | + super.onCreate(); | |
| 64 | + IntentFilter filter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION); | |
| 65 | + netConnectionReceiver = new NetConnectionReceiver(); | |
| 66 | + registerReceiver(netConnectionReceiver, filter); | |
| 67 | + } | |
| 68 | + | |
| 69 | + @Override | |
| 70 | + public IBinder onBind(Intent intent) { | |
| 71 | + return null; | |
| 72 | + } | |
| 73 | + | |
| 74 | + @Override | |
| 75 | + public void onDestroy() { | |
| 76 | + super.onDestroy(); | |
| 77 | + unregisterReceiver(netConnectionReceiver); | |
| 78 | + } | |
| 79 | + | |
| 80 | + //用于Service和MyThread之间的通信 | |
| 81 | + @SuppressLint("HandlerLeak") | |
| 82 | + Handler mHandle = new Handler() { | |
| 83 | + @Override | |
| 84 | + public void handleMessage(Message msg) { | |
| 85 | + DownloadInfo info = (DownloadInfo) msg.obj; | |
| 86 | + switch (msg.what) { | |
| 87 | + case 0: | |
| 88 | + //启动一个下载任务 | |
| 89 | + DownloadLimitManager.getInstance().download(info); | |
| 90 | + break; | |
| 91 | + case 1://暂停一个 | |
| 92 | + DownloadLimitManager.getInstance().pauseDownload(info,false); | |
| 93 | + break; | |
| 94 | + case 2://全部暂停 | |
| 95 | + DownloadLimitManager.getInstance().pauseAllDownload(); | |
| 96 | + break; | |
| 97 | + case 3: | |
| 98 | + DownloadLimitManager.getInstance().startAllDownload(); | |
| 99 | + break; | |
| 100 | + case 4: | |
| 101 | + DownloadLimitManager.getInstance().cancelDownload(info,true); | |
| 102 | + break; | |
| 103 | + case 5: | |
| 104 | + DownloadLimitManager.getInstance().clearDownload(); | |
| 105 | + break; | |
| 106 | + case 6: | |
| 107 | + DownloadLimitManager.getInstance().pauseToWaitDownload(info); | |
| 108 | + break; | |
| 109 | + } | |
| 110 | + } | |
| 111 | + }; | |
| 112 | + | |
| 113 | + | |
| 114 | + //子线程 获取文件长度 | |
| 115 | + class MyThread extends Thread { | |
| 116 | + private DownloadInfo fileInfo = null; | |
| 117 | + public MyThread(DownloadInfo fileInfo) { | |
| 118 | + this.fileInfo = fileInfo; | |
| 119 | + } | |
| 120 | + public void run() { | |
| 121 | + mHandle.obtainMessage(0, fileInfo).sendToTarget(); | |
| 122 | + } | |
| 123 | + } | |
| 124 | + | |
| 125 | + private class NetConnectionReceiver extends BroadcastReceiver { | |
| 126 | + | |
| 127 | + @Override | |
| 128 | + public void onReceive(Context context, Intent intent) { | |
| 129 | + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); | |
| 130 | + NetworkInfo mobNetInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); | |
| 131 | + NetworkInfo wifiNetInfo = connectivityManager.getNetworkInfo(ConnectivityManager.TYPE_WIFI); | |
| 132 | + | |
| 133 | + if (!mobNetInfo.isConnected() && !wifiNetInfo.isConnected()) { | |
| 134 | + //网络断开 | |
| 135 | + if(DownloadLimitManager.getInstance().getCurremtDownload() !=null && DownloadLimitManager.getInstance().getCurremtDownload().getUrl() != null){ | |
| 136 | + DownloadLimitManager.getInstance().pauseErrorDownload(); | |
| 137 | + } | |
| 138 | + } else { | |
| 139 | + //网络连接 | |
| 140 | + //启动初始化线程 | |
| 141 | + if(DownloadLimitManager.getInstance().getCurremtDownload() !=null && DownloadLimitManager.getInstance().getCurremtDownload().getUrl() != null){ | |
| 142 | + new MyThread(DownloadLimitManager.getInstance().getCurremtDownload()).start(); | |
| 143 | + } | |
| 144 | + } | |
| 145 | + } | |
| 146 | + } | |
| 147 | +} | |
| 0 | 148 | \ No newline at end of file | ... | ... |
app/src/main/java/com/cnlive/downloadfile/download/limit/DownloadIO.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/download/limit/DownloadIO.java | |
| 1 | +package com.cnlive.downloadfile.download.limit; | |
| 2 | + | |
| 3 | +import java.io.Closeable; | |
| 4 | +import java.io.IOException; | |
| 5 | + | |
| 6 | +public class DownloadIO { | |
| 7 | + public static void closeAll(Closeable... closeables){ | |
| 8 | + if(closeables == null){ | |
| 9 | + return; | |
| 10 | + } | |
| 11 | + for (Closeable closeable : closeables) { | |
| 12 | + if(closeable!=null){ | |
| 13 | + try { | |
| 14 | + closeable.close(); | |
| 15 | + } catch (IOException e) { | |
| 16 | + e.printStackTrace(); | |
| 17 | + } | |
| 18 | + } | |
| 19 | + } | |
| 20 | + } | |
| 21 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/download/limit/DownloadInfo.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/download/limit/DownloadInfo.java | |
| 1 | +package com.cnlive.downloadfile.download.limit; | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | +import org.greenrobot.greendao.annotation.Entity; | |
| 6 | + | |
| 7 | +import org.greenrobot.greendao.annotation.Generated; | |
| 8 | +import org.greenrobot.greendao.annotation.Id; | |
| 9 | +import org.greenrobot.greendao.annotation.Unique; | |
| 10 | + | |
| 11 | +import java.io.Serializable; | |
| 12 | + | |
| 13 | +@Entity | |
| 14 | +public class DownloadInfo implements Serializable { | |
| 15 | + | |
| 16 | + @Id | |
| 17 | + private long id; | |
| 18 | + @Unique | |
| 19 | + private String url; | |
| 20 | + private String fileName; | |
| 21 | + private String downloadStatus; | |
| 22 | + private long total; | |
| 23 | + private long progress; | |
| 24 | + private String title; | |
| 25 | + static final long serialVersionUID = 42L; | |
| 26 | + @Generated(hash = 1825047729) | |
| 27 | + public DownloadInfo(long id, String url, String fileName, String downloadStatus, | |
| 28 | + long total, long progress, String title) { | |
| 29 | + this.id = id; | |
| 30 | + this.url = url; | |
| 31 | + this.fileName = fileName; | |
| 32 | + this.downloadStatus = downloadStatus; | |
| 33 | + this.total = total; | |
| 34 | + this.progress = progress; | |
| 35 | + this.title = title; | |
| 36 | + } | |
| 37 | + @Generated(hash = 327086747) | |
| 38 | + public DownloadInfo() { | |
| 39 | + } | |
| 40 | + public long getId() { | |
| 41 | + return this.id; | |
| 42 | + } | |
| 43 | + public void setId(long id) { | |
| 44 | + this.id = id; | |
| 45 | + } | |
| 46 | + public String getUrl() { | |
| 47 | + return this.url; | |
| 48 | + } | |
| 49 | + public void setUrl(String url) { | |
| 50 | + this.url = url; | |
| 51 | + } | |
| 52 | + public String getFileName() { | |
| 53 | + return this.fileName; | |
| 54 | + } | |
| 55 | + public void setFileName(String fileName) { | |
| 56 | + this.fileName = fileName; | |
| 57 | + } | |
| 58 | + public String getDownloadStatus() { | |
| 59 | + return this.downloadStatus; | |
| 60 | + } | |
| 61 | + public void setDownloadStatus(String downloadStatus) { | |
| 62 | + this.downloadStatus = downloadStatus; | |
| 63 | + } | |
| 64 | + public long getTotal() { | |
| 65 | + return this.total; | |
| 66 | + } | |
| 67 | + public void setTotal(long total) { | |
| 68 | + this.total = total; | |
| 69 | + } | |
| 70 | + public long getProgress() { | |
| 71 | + return this.progress; | |
| 72 | + } | |
| 73 | + public void setProgress(long progress) { | |
| 74 | + this.progress = progress; | |
| 75 | + } | |
| 76 | + public String getTitle() { | |
| 77 | + return this.title; | |
| 78 | + } | |
| 79 | + public void setTitle(String title) { | |
| 80 | + this.title = title; | |
| 81 | + } | |
| 82 | + | |
| 83 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/download/limit/DownloadLimitManager.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/download/limit/DownloadLimitManager.java | |
| 1 | +package com.cnlive.downloadfile.download.limit; | |
| 2 | + | |
| 3 | +import com.cnlive.downloadfile.Constant; | |
| 4 | +import com.cnlive.downloadfile.MyApplication; | |
| 5 | + | |
| 6 | +import org.greenrobot.eventbus.EventBus; | |
| 7 | + | |
| 8 | +import java.io.File; | |
| 9 | +import java.io.FileOutputStream; | |
| 10 | +import java.io.IOException; | |
| 11 | +import java.io.InputStream; | |
| 12 | +import java.util.ArrayList; | |
| 13 | +import java.util.HashMap; | |
| 14 | +import java.util.List; | |
| 15 | +import java.util.concurrent.atomic.AtomicReference; | |
| 16 | + | |
| 17 | +import io.reactivex.Observable; | |
| 18 | +import io.reactivex.ObservableEmitter; | |
| 19 | +import io.reactivex.ObservableOnSubscribe; | |
| 20 | +import io.reactivex.ObservableSource; | |
| 21 | +import io.reactivex.android.schedulers.AndroidSchedulers; | |
| 22 | +import io.reactivex.functions.Function; | |
| 23 | +import io.reactivex.functions.Predicate; | |
| 24 | +import io.reactivex.schedulers.Schedulers; | |
| 25 | +import okhttp3.Call; | |
| 26 | +import okhttp3.OkHttpClient; | |
| 27 | +import okhttp3.Request; | |
| 28 | +import okhttp3.Response; | |
| 29 | + | |
| 30 | +/** | |
| 31 | + * About: 下载管理(限制最大个数) | |
| 32 | + */ | |
| 33 | +public class DownloadLimitManager { | |
| 34 | + | |
| 35 | + private static final AtomicReference<DownloadLimitManager> INSTANCE = new AtomicReference<>(); | |
| 36 | + private OkHttpClient mClient; | |
| 37 | + private HashMap<String, Call> downCalls; // 用来存放各个下载的请求 | |
| 38 | + private List<DownloadInfo> downWait; // 用来存放等待下载的请求 | |
| 39 | + private DownloadInfo currentDownInfo; | |
| 40 | + | |
| 41 | + public static DownloadLimitManager getInstance() { | |
| 42 | + for (; ; ) { | |
| 43 | + DownloadLimitManager current = INSTANCE.get(); | |
| 44 | + if (current != null) { | |
| 45 | + return current; | |
| 46 | + } | |
| 47 | + current = new DownloadLimitManager(); | |
| 48 | + if (INSTANCE.compareAndSet(null, current)) { | |
| 49 | + return current; | |
| 50 | + } | |
| 51 | + } | |
| 52 | + } | |
| 53 | + | |
| 54 | + private DownloadLimitManager() { | |
| 55 | + downCalls = new HashMap<>(); | |
| 56 | + mClient = new OkHttpClient.Builder().build(); | |
| 57 | + downWait = new ArrayList<>(); | |
| 58 | + } | |
| 59 | + | |
| 60 | + /** | |
| 61 | + * 查看是否在下载任务中 | |
| 62 | + * | |
| 63 | + * @param url | |
| 64 | + * @return | |
| 65 | + */ | |
| 66 | + public boolean getDownloadUrl(String url) { | |
| 67 | + return downCalls.containsKey(url); | |
| 68 | + } | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * 查看是否在等待任务中 | |
| 72 | + * | |
| 73 | + * @param url | |
| 74 | + * @return | |
| 75 | + */ | |
| 76 | + public boolean getWaitUrl(String url) { | |
| 77 | + for (DownloadInfo item : downWait) { | |
| 78 | + if (item.getUrl().equals(url)) { | |
| 79 | + return true; | |
| 80 | + } | |
| 81 | + } | |
| 82 | + return false; | |
| 83 | + } | |
| 84 | + | |
| 85 | + /** | |
| 86 | + * 开始下载 | |
| 87 | + * | |
| 88 | + * @param downloadInfo 下载请求的网址 | |
| 89 | + */ | |
| 90 | + public void download(final DownloadInfo downloadInfo) { | |
| 91 | + List<DownloadInfo> list = MyApplication.getInstances().getDaoSession().loadAll(DownloadInfo.class); | |
| 92 | + downWait.clear(); | |
| 93 | + downWait = list; | |
| 94 | + if (currentDownInfo != null) pauseDownload(currentDownInfo, true); | |
| 95 | + if (downCalls.containsKey(downloadInfo.getUrl())) downCalls.remove(downloadInfo.getUrl()); | |
| 96 | + Observable.just(downloadInfo.getUrl()) | |
| 97 | + .filter(new Predicate<String>() { // 过滤 call的map中已经有了,就证明正在下载,则这次不下载 | |
| 98 | + @Override | |
| 99 | + public boolean test(String s) { | |
| 100 | + boolean flag = downCalls.containsKey(s); | |
| 101 | + if (flag) { | |
| 102 | + // 如果已经在下载,并且不是暂停的数据,查找下一个文件进行下载 | |
| 103 | + downNext(); | |
| 104 | + return false; | |
| 105 | + } else { | |
| 106 | + // 判断如果正在下载的个数达到最大限制,存到等下下载列表中 | |
| 107 | + return true; | |
| 108 | + } | |
| 109 | + } | |
| 110 | + }) | |
| 111 | + .flatMap(new Function<String, ObservableSource<?>>() { // 生成 DownloadInfo | |
| 112 | + @Override | |
| 113 | + public ObservableSource<?> apply(String s) { | |
| 114 | + return Observable.just(createDownInfo(downloadInfo)); | |
| 115 | + } | |
| 116 | + }) | |
| 117 | + .map(new Function<Object, DownloadInfo>() { // 如果已经下载,重新命名 | |
| 118 | + @Override | |
| 119 | + public DownloadInfo apply(Object o) { | |
| 120 | + return getRealFileName((DownloadInfo) o); | |
| 121 | + } | |
| 122 | + }) | |
| 123 | + .flatMap(new Function<DownloadInfo, ObservableSource<DownloadInfo>>() { // 下载 | |
| 124 | + @Override | |
| 125 | + public ObservableSource<DownloadInfo> apply(DownloadInfo downloadInfo) { | |
| 126 | + currentDownInfo = downloadInfo; | |
| 127 | + return Observable.create(new DownloadSubscribe(downloadInfo)); | |
| 128 | + } | |
| 129 | + }) | |
| 130 | + .observeOn(AndroidSchedulers.mainThread()) // 在主线程中回调 | |
| 131 | + .subscribeOn(Schedulers.io()) // 在子线程中执行 | |
| 132 | + .subscribe(new DownloadLimitObserver()); // 添加观察者,监听下载进度 | |
| 133 | + } | |
| 134 | + | |
| 135 | + /** | |
| 136 | + * 下载等待下载中的第一条 | |
| 137 | + */ | |
| 138 | + public void downNext() { | |
| 139 | + for (int i = 0; i < downWait.size(); i++) { | |
| 140 | + if (!downCalls.containsKey(downWait.get(i).getUrl()) && !downWait.get(i).getUrl().equals(currentDownInfo)) { | |
| 141 | + download(downWait.get(i)); | |
| 142 | + break; | |
| 143 | + } | |
| 144 | + } | |
| 145 | + } | |
| 146 | + | |
| 147 | + /** | |
| 148 | + * 下载取消或者暂停 | |
| 149 | + * | |
| 150 | + * @param downloadInfo | |
| 151 | + * @param isPauseCurrent 点击开始下载,那正在下载的文件要暂停,并且执行点击的item,不进行next | |
| 152 | + */ | |
| 153 | + public void pauseDownload(DownloadInfo downloadInfo, boolean isPauseCurrent) { | |
| 154 | + Call call = downCalls.get(downloadInfo.getUrl()); | |
| 155 | + if (call != null) { | |
| 156 | + call.cancel();//取消 | |
| 157 | + } | |
| 158 | + downloadInfo.setDownloadStatus(DownloadStatus.DOWNLOAD_PAUSE); | |
| 159 | + MyApplication.getInstances().getDaoSession().update(downloadInfo); | |
| 160 | + EventBus.getDefault().post(downloadInfo);//通知页面 | |
| 161 | + for(int i = 0;i < downWait.size();i++){ | |
| 162 | + if(downWait.get(i).getUrl().equals(downloadInfo.getUrl())){ | |
| 163 | + downWait.set(i,downloadInfo); | |
| 164 | + break; | |
| 165 | + } | |
| 166 | + } | |
| 167 | + //如果暂停的当前文件,next | |
| 168 | + if (currentDownInfo != null && downloadInfo.getUrl().equals(currentDownInfo.getUrl()) && !isPauseCurrent) { | |
| 169 | + downNext(); | |
| 170 | + } else { | |
| 171 | + downCalls.put(downloadInfo.getUrl(), null); | |
| 172 | + } | |
| 173 | + } | |
| 174 | + | |
| 175 | + /** | |
| 176 | + * 出错暂停,突然断网 | |
| 177 | + */ | |
| 178 | + public void pauseErrorDownload() { | |
| 179 | + if (currentDownInfo != null) { | |
| 180 | + Call call = downCalls.get(currentDownInfo); | |
| 181 | + if (call != null) { | |
| 182 | + call.cancel();//取消 | |
| 183 | + } | |
| 184 | + downCalls.remove(currentDownInfo.getUrl()); | |
| 185 | + } | |
| 186 | + } | |
| 187 | + | |
| 188 | + | |
| 189 | + /** | |
| 190 | + * 暂停状态转变为等待状态 | |
| 191 | + * @param downloadInfo | |
| 192 | + */ | |
| 193 | + public void pauseToWaitDownload(DownloadInfo downloadInfo){ | |
| 194 | + boolean hasWaiting = false; | |
| 195 | + int downIndex = 0; | |
| 196 | + for(int i = 0;i < downWait.size();i++){ | |
| 197 | + if(downWait.get(i).getUrl().equals(downloadInfo.getUrl())){ | |
| 198 | + downIndex = i; | |
| 199 | + if(hasWaiting){ | |
| 200 | + break; | |
| 201 | + } | |
| 202 | + } | |
| 203 | + if(downWait.get(i).getDownloadStatus().equals(DownloadStatus.DOWNLOAD_WAIT) || downWait.get(i).getDownloadStatus().equals(DownloadStatus.DOWNLOAD)){ | |
| 204 | + hasWaiting = true; | |
| 205 | + if(downIndex != 0) { | |
| 206 | + break; | |
| 207 | + } | |
| 208 | + } | |
| 209 | + } | |
| 210 | + if(hasWaiting){ | |
| 211 | + downloadInfo.setDownloadStatus(DownloadStatus.DOWNLOAD_WAIT); | |
| 212 | + downCalls.remove(downloadInfo.getUrl()); | |
| 213 | + EventBus.getDefault().post(downloadInfo);//通知页面 | |
| 214 | + }else { | |
| 215 | + downloadInfo.setDownloadStatus(DownloadStatus.DOWNLOAD); | |
| 216 | + download(downloadInfo); | |
| 217 | + } | |
| 218 | + downWait.set(downIndex,downloadInfo); | |
| 219 | + MyApplication.getInstances().getDaoSession().update(downloadInfo);//更新数据库状态 | |
| 220 | + } | |
| 221 | + | |
| 222 | + /** | |
| 223 | + * 暂停所有的下载 | |
| 224 | + */ | |
| 225 | + public void pauseAllDownload() { | |
| 226 | + for (int i = 0; i < downWait.size(); i++) { | |
| 227 | + Call call = downCalls.get(downWait.get(i).getUrl()); | |
| 228 | + if (call != null) { | |
| 229 | + call.cancel(); | |
| 230 | + if(currentDownInfo != null && downWait.get(i).getUrl() .equals(currentDownInfo.getUrl())){ | |
| 231 | + downWait.set(i,currentDownInfo); | |
| 232 | + } | |
| 233 | + }else { | |
| 234 | + downCalls.put(downWait.get(i).getUrl(),null); | |
| 235 | + } | |
| 236 | + downWait.get(i).setDownloadStatus(DownloadStatus.DOWNLOAD_PAUSE);//改变状态 | |
| 237 | + MyApplication.getInstances().getDaoSession().update(downWait.get(i));//更新数据库状态 | |
| 238 | + } | |
| 239 | + if(currentDownInfo != null){ | |
| 240 | + EventBus.getDefault().post(currentDownInfo);//通知页面 | |
| 241 | + currentDownInfo = null; | |
| 242 | + } | |
| 243 | + } | |
| 244 | + | |
| 245 | + /** | |
| 246 | + * 全部开始 | |
| 247 | + */ | |
| 248 | + public void startAllDownload() { | |
| 249 | + downCalls.clear(); | |
| 250 | + downWait.clear(); | |
| 251 | + List<DownloadInfo> list = MyApplication.getInstances().getDaoSession().loadAll(DownloadInfo.class); | |
| 252 | + downWait = list; | |
| 253 | + if (downWait.size() > 0) { | |
| 254 | + for (int i = 0; i < downWait.size(); i++) { | |
| 255 | + downWait.get(i).setDownloadStatus(DownloadStatus.DOWNLOAD_WAIT);//改变状态 | |
| 256 | + MyApplication.getInstances().getDaoSession().update(downWait.get(i));//更新数据库状态 | |
| 257 | +// EventBus.getDefault().post(downWait.get(i));//通知页面 | |
| 258 | + } | |
| 259 | + download(downWait.get(0)); | |
| 260 | + } | |
| 261 | + } | |
| 262 | + | |
| 263 | + | |
| 264 | + /** | |
| 265 | + * 全部删除清空 | |
| 266 | + */ | |
| 267 | + public void clearDownload() { | |
| 268 | + for (int i = 0; i < downWait.size(); i++) { | |
| 269 | + Call call = downCalls.get(currentDownInfo); | |
| 270 | + if (call != null) { | |
| 271 | + call.cancel();//取消 | |
| 272 | + } | |
| 273 | + Constant.deleteFile(downWait.get(i).getUrl().substring(downWait.get(i).getUrl().lastIndexOf("/"))); | |
| 274 | + } | |
| 275 | + currentDownInfo = null; | |
| 276 | + downWait.clear(); | |
| 277 | + downCalls.clear(); | |
| 278 | + MyApplication.getInstances().getDaoSession().deleteAll(DownloadInfo.class); | |
| 279 | + } | |
| 280 | + | |
| 281 | + /** | |
| 282 | + * 取消下载 删除本地文件 | |
| 283 | + * | |
| 284 | + * @param info | |
| 285 | + */ | |
| 286 | + public void cancelDownload(DownloadInfo info, boolean fileDelect) { | |
| 287 | + //本地数据操作 | |
| 288 | + for (int i = 0; i < downWait.size(); i++) { | |
| 289 | + if (downWait.get(i).getUrl().equals(info.getUrl())) { | |
| 290 | + downWait.remove(i); | |
| 291 | + MyApplication.getInstances().getDaoSession().delete(info); | |
| 292 | + break; | |
| 293 | + } | |
| 294 | + } | |
| 295 | + downCalls.remove(info); | |
| 296 | + info.setDownloadStatus(DownloadStatus.DOWNLOAD_CANCEL); | |
| 297 | + EventBus.getDefault().post(info); | |
| 298 | + if (fileDelect) Constant.deleteFile(info.getFileName()); | |
| 299 | + | |
| 300 | + Call call = downCalls.get(info.getUrl()); | |
| 301 | + if (call != null) { | |
| 302 | + call.cancel();//取消 | |
| 303 | + } | |
| 304 | + //如果暂停的当前文件,next | |
| 305 | + if (currentDownInfo != null && info.getUrl().equals(currentDownInfo.getUrl())) { | |
| 306 | + downNext(); | |
| 307 | + } | |
| 308 | + } | |
| 309 | + | |
| 310 | + /** | |
| 311 | + * 得到当前正在下载的任务 | |
| 312 | + * | |
| 313 | + * @return | |
| 314 | + */ | |
| 315 | + public DownloadInfo getCurremtDownload() { | |
| 316 | + return currentDownInfo; | |
| 317 | + } | |
| 318 | + | |
| 319 | + /** | |
| 320 | + * 创建DownInfo | |
| 321 | + * | |
| 322 | + * @param downloadInfo 请求网址 | |
| 323 | + * @return DownInfo | |
| 324 | + */ | |
| 325 | + private DownloadInfo createDownInfo(DownloadInfo downloadInfo) { | |
| 326 | + long contentLength = getContentLength(downloadInfo.getUrl());//获得文件大小 | |
| 327 | + downloadInfo.setTotal(contentLength); | |
| 328 | + String fileName = downloadInfo.getUrl().substring(downloadInfo.getUrl().lastIndexOf("/")); | |
| 329 | + downloadInfo.setFileName(fileName); | |
| 330 | + return downloadInfo; | |
| 331 | + } | |
| 332 | + | |
| 333 | + /** | |
| 334 | + * 如果文件已下载重新命名新文件名 | |
| 335 | + * | |
| 336 | + * @param downloadInfo | |
| 337 | + * @return | |
| 338 | + */ | |
| 339 | + private DownloadInfo getRealFileName(DownloadInfo downloadInfo) { | |
| 340 | + String fileName = downloadInfo.getFileName(); | |
| 341 | + long downloadLength = 0, contentLength = downloadInfo.getTotal(); | |
| 342 | + File path = new File(Constant.FILE_PATH); | |
| 343 | + if (!path.exists()) { | |
| 344 | + path.mkdir(); | |
| 345 | + } | |
| 346 | + File file = new File(Constant.FILE_PATH, fileName); | |
| 347 | + if (file.exists()) { | |
| 348 | + //找到了文件,代表已经下载过,则获取其长度 | |
| 349 | + downloadLength = file.length(); | |
| 350 | + } | |
| 351 | + //之前下载过,需要重新来一个文件 | |
| 352 | + int i = 1; | |
| 353 | + while (downloadLength >= contentLength) { | |
| 354 | + int dotIndex = fileName.lastIndexOf("."); | |
| 355 | + String fileNameOther; | |
| 356 | + if (dotIndex == -1) { | |
| 357 | + fileNameOther = fileName + "(" + i + ")"; | |
| 358 | + } else { | |
| 359 | + fileNameOther = fileName.substring(0, dotIndex) | |
| 360 | + + "(" + i + ")" + fileName.substring(dotIndex); | |
| 361 | + } | |
| 362 | + File newFile = new File(Constant.FILE_PATH, fileNameOther); | |
| 363 | + file = newFile; | |
| 364 | + downloadLength = newFile.length(); | |
| 365 | + i++; | |
| 366 | + } | |
| 367 | + //设置改变过的文件名/大小 | |
| 368 | + downloadInfo.setProgress(downloadLength); | |
| 369 | + downloadInfo.setFileName(file.getName()); | |
| 370 | + return downloadInfo; | |
| 371 | + } | |
| 372 | + | |
| 373 | + private class DownloadSubscribe implements ObservableOnSubscribe<DownloadInfo> { | |
| 374 | + private DownloadInfo downloadInfo; | |
| 375 | + | |
| 376 | + public DownloadSubscribe(DownloadInfo downloadInfo) { | |
| 377 | + this.downloadInfo = downloadInfo; | |
| 378 | + } | |
| 379 | + | |
| 380 | + @Override | |
| 381 | + public void subscribe(ObservableEmitter<DownloadInfo> e) throws Exception { | |
| 382 | + String url = downloadInfo.getUrl(); | |
| 383 | + long downloadLength = downloadInfo.getProgress();//已经下载好的长度 | |
| 384 | + long contentLength = downloadInfo.getTotal();//文件的总长度 | |
| 385 | + //初始进度信息 | |
| 386 | + e.onNext(downloadInfo); | |
| 387 | + Request request = new Request.Builder() | |
| 388 | + //确定下载的范围,添加此头,则服务器就可以跳过已经下载好的部分 | |
| 389 | + .addHeader("RANGE", "bytes=" + downloadLength + "-" + contentLength) | |
| 390 | + .url(url) | |
| 391 | + .build(); | |
| 392 | + Call call = mClient.newCall(request); | |
| 393 | + downCalls.put(url, call);//把这个添加到call里,方便取消 | |
| 394 | + | |
| 395 | + Response response = call.execute(); | |
| 396 | + File file = new File(Constant.FILE_PATH, downloadInfo.getFileName()); | |
| 397 | + InputStream is = null; | |
| 398 | + FileOutputStream fileOutputStream = null; | |
| 399 | + try { | |
| 400 | + is = response.body().byteStream(); | |
| 401 | + fileOutputStream = new FileOutputStream(file, true); | |
| 402 | + byte[] buffer = new byte[2048];//缓冲数组2kB | |
| 403 | + int len; | |
| 404 | + while ((len = is.read(buffer)) != -1) { | |
| 405 | + fileOutputStream.write(buffer, 0, len); | |
| 406 | + downloadLength += len; | |
| 407 | + downloadInfo.setProgress(downloadLength); | |
| 408 | + currentDownInfo.setProgress(downloadLength); | |
| 409 | + e.onNext(downloadInfo); | |
| 410 | + } | |
| 411 | + fileOutputStream.flush(); | |
| 412 | + for (int i = 0; i < downWait.size(); i++) { | |
| 413 | + if (downWait.get(i).getUrl().equals(url)) { | |
| 414 | + MyApplication.getInstances().getDaoSession().delete(downWait.get(i)); | |
| 415 | + downWait.remove(i); | |
| 416 | + downCalls.remove(url); | |
| 417 | + currentDownInfo = null; | |
| 418 | + downNext(); | |
| 419 | + break; | |
| 420 | + } | |
| 421 | + } | |
| 422 | + } finally { | |
| 423 | + //关闭IO流 | |
| 424 | + DownloadIO.closeAll(is, fileOutputStream); | |
| 425 | + | |
| 426 | + } | |
| 427 | + e.onComplete();//完成 | |
| 428 | + } | |
| 429 | + } | |
| 430 | + | |
| 431 | + | |
| 432 | + /** | |
| 433 | + * 获取下载长度 | |
| 434 | + * | |
| 435 | + * @param downloadUrl | |
| 436 | + * @return | |
| 437 | + */ | |
| 438 | + private long getContentLength(String downloadUrl) { | |
| 439 | + Request request = new Request.Builder() | |
| 440 | + .url(downloadUrl) | |
| 441 | + .build(); | |
| 442 | + try { | |
| 443 | + Response response = mClient.newCall(request).execute(); | |
| 444 | + if (response != null && response.isSuccessful()) { | |
| 445 | + long contentLength = response.body().contentLength(); | |
| 446 | + response.close(); | |
| 447 | + return contentLength == 0 ? DownloadStatus.TOTAL_ERROR : contentLength; | |
| 448 | + } | |
| 449 | + } catch (IOException e) { | |
| 450 | + e.printStackTrace(); | |
| 451 | + } | |
| 452 | + return DownloadStatus.TOTAL_ERROR; | |
| 453 | + } | |
| 454 | + | |
| 455 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/download/limit/DownloadLimitObserver.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/download/limit/DownloadLimitObserver.java | |
| 1 | +package com.cnlive.downloadfile.download.limit; | |
| 2 | + | |
| 3 | +import org.greenrobot.eventbus.EventBus; | |
| 4 | + | |
| 5 | +import io.reactivex.Observer; | |
| 6 | +import io.reactivex.disposables.Disposable; | |
| 7 | + | |
| 8 | +/** | |
| 9 | + * 观察者 | |
| 10 | + */ | |
| 11 | +public class DownloadLimitObserver implements Observer<DownloadInfo> { | |
| 12 | + | |
| 13 | + public Disposable d;//可以用于取消注册的监听者 | |
| 14 | + public DownloadInfo downloadInfo; | |
| 15 | + | |
| 16 | + @Override | |
| 17 | + public void onSubscribe(Disposable d) { | |
| 18 | + this.d = d; | |
| 19 | + } | |
| 20 | + | |
| 21 | + @Override | |
| 22 | + public void onNext(DownloadInfo value) { | |
| 23 | + this.downloadInfo = value; | |
| 24 | + downloadInfo.setDownloadStatus(DownloadStatus.DOWNLOAD); | |
| 25 | + EventBus.getDefault().post(downloadInfo); | |
| 26 | + } | |
| 27 | + | |
| 28 | + @Override | |
| 29 | + public void onError(Throwable e) { | |
| 30 | +// Log.d("My_Log","onError"); | |
| 31 | +// if (downloadInfo.getUrl() != null && DownloadLimitManager.getInstance().getDownloadUrl(downloadInfo.getUrl())){ | |
| 32 | +// DownloadLimitManager.getInstance().pauseDownload(downloadInfo.getUrl()); | |
| 33 | +// downloadInfo.setDownloadStatus(DownloadStatus.DOWNLOAD_ERROR); | |
| 34 | +// EventBus.getDefault().post(downloadInfo); | |
| 35 | +// }else{ | |
| 36 | +// downloadInfo.setDownloadStatus(DownloadStatus.DOWNLOAD_PAUSE); | |
| 37 | +// EventBus.getDefault().post(downloadInfo); | |
| 38 | +// } | |
| 39 | + } | |
| 40 | + | |
| 41 | + @Override | |
| 42 | + public void onComplete() { | |
| 43 | + if (downloadInfo != null){ | |
| 44 | + downloadInfo.setDownloadStatus(DownloadStatus.DOWNLOAD_OVER); | |
| 45 | + EventBus.getDefault().post(downloadInfo); | |
| 46 | + } | |
| 47 | + } | |
| 48 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/download/limit/DownloadStatus.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/download/limit/DownloadStatus.java | |
| 1 | +package com.cnlive.downloadfile.download.limit; | |
| 2 | + | |
| 3 | +public class DownloadStatus { | |
| 4 | + /** | |
| 5 | + * 下载状态 | |
| 6 | + */ | |
| 7 | + public static final String DOWNLOAD = "download"; // 下载中 | |
| 8 | + public static final String DOWNLOAD_PAUSE = "pause"; // 下载暂停 | |
| 9 | + public static final String DOWNLOAD_WAIT = "wait"; // 等待下载 | |
| 10 | + public static final String DOWNLOAD_CANCEL = "cancel"; // 下载取消 | |
| 11 | + public static final String DOWNLOAD_OVER = "over"; // 下载结束 | |
| 12 | + public static final String DOWNLOAD_ERROR = "error"; // 下载出错 | |
| 13 | + | |
| 14 | + public static final long TOTAL_ERROR = -1;//获取进度失败 | |
| 15 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/download/util/CheckNetworkStatusChangeListener.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/download/util/CheckNetworkStatusChangeListener.java | |
| 1 | +package com.cnlive.downloadfile.download.util; | |
| 2 | + | |
| 3 | +public interface CheckNetworkStatusChangeListener { | |
| 4 | + | |
| 5 | + void onEvent(Status status); | |
| 6 | + | |
| 7 | + /** | |
| 8 | + * 网络状态 | |
| 9 | + * TYPE_UN_NETWORK 沒有网络 | |
| 10 | + * TYPE_WIFI WiFi连接 | |
| 11 | + * TYPE_MOBILE 移动数据 | |
| 12 | + */ | |
| 13 | + enum Status { | |
| 14 | + TYPE_UN_NETWORK, | |
| 15 | + TYPE_WIFI, | |
| 16 | + TYPE_MOBILE, | |
| 17 | + } | |
| 18 | +} | ... | ... |
app/src/main/java/com/cnlive/downloadfile/download/util/NetWorkUtil.java
0 → 100644
| 1 | +++ a/app/src/main/java/com/cnlive/downloadfile/download/util/NetWorkUtil.java | |
| 1 | +package com.cnlive.downloadfile.download.util; | |
| 2 | + | |
| 3 | + | |
| 4 | +import android.content.Context; | |
| 5 | +import android.net.ConnectivityManager; | |
| 6 | +import android.net.NetworkInfo; | |
| 7 | + | |
| 8 | +public class NetWorkUtil { | |
| 9 | + /** | |
| 10 | + * 获取当前网络类型 CheckNetworkStatusChangeListener.Status | |
| 11 | + * | |
| 12 | + * @return 返回网络类型 CheckNetworkStatusChangeListener.Status | |
| 13 | + */ | |
| 14 | + public static CheckNetworkStatusChangeListener.Status getNetworkConnectionType(Context context) { | |
| 15 | + //获取连接管理器 | |
| 16 | + ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); | |
| 17 | + if (connectivityManager == null) | |
| 18 | + return CheckNetworkStatusChangeListener.Status.TYPE_UN_NETWORK; | |
| 19 | + //获取网络连接信息 | |
| 20 | + NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo(); | |
| 21 | + if (networkInfo != null && networkInfo.isAvailable()) { | |
| 22 | + if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) { | |
| 23 | + return CheckNetworkStatusChangeListener.Status.TYPE_WIFI; | |
| 24 | + } | |
| 25 | + if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) { | |
| 26 | + return CheckNetworkStatusChangeListener.Status.TYPE_MOBILE; | |
| 27 | + } | |
| 28 | + } | |
| 29 | + return CheckNetworkStatusChangeListener.Status.TYPE_UN_NETWORK; | |
| 30 | + } | |
| 31 | +} | |
| 0 | 32 | \ No newline at end of file | ... | ... |
app/src/main/res/drawable-v24/ic_launcher_foreground.xml
0 → 100644
| 1 | +++ a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml | |
| 1 | +<vector xmlns:android="http://schemas.android.com/apk/res/android" | |
| 2 | + xmlns:aapt="http://schemas.android.com/aapt" | |
| 3 | + android:width="108dp" | |
| 4 | + android:height="108dp" | |
| 5 | + android:viewportHeight="108" | |
| 6 | + android:viewportWidth="108"> | |
| 7 | + <path | |
| 8 | + android:fillType="evenOdd" | |
| 9 | + android:pathData="M32,64C32,64 38.39,52.99 44.13,50.95C51.37,48.37 70.14,49.57 70.14,49.57L108.26,87.69L108,109.01L75.97,107.97L32,64Z" | |
| 10 | + android:strokeColor="#00000000" | |
| 11 | + android:strokeWidth="1"> | |
| 12 | + <aapt:attr name="android:fillColor"> | |
| 13 | + <gradient | |
| 14 | + android:endX="78.5885" | |
| 15 | + android:endY="90.9159" | |
| 16 | + android:startX="48.7653" | |
| 17 | + android:startY="61.0927" | |
| 18 | + android:type="linear"> | |
| 19 | + <item | |
| 20 | + android:color="#44000000" | |
| 21 | + android:offset="0.0" /> | |
| 22 | + <item | |
| 23 | + android:color="#00000000" | |
| 24 | + android:offset="1.0" /> | |
| 25 | + </gradient> | |
| 26 | + </aapt:attr> | |
| 27 | + </path> | |
| 28 | + <path | |
| 29 | + android:fillColor="#FFFFFF" | |
| 30 | + android:fillType="nonZero" | |
| 31 | + android:pathData="M66.94,46.02L66.94,46.02C72.44,50.07 76,56.61 76,64L32,64C32,56.61 35.56,50.11 40.98,46.06L36.18,41.19C35.45,40.45 35.45,39.3 36.18,38.56C36.91,37.81 38.05,37.81 38.78,38.56L44.25,44.05C47.18,42.57 50.48,41.71 54,41.71C57.48,41.71 60.78,42.57 63.68,44.05L69.11,38.56C69.84,37.81 70.98,37.81 71.71,38.56C72.44,39.3 72.44,40.45 71.71,41.19L66.94,46.02ZM62.94,56.92C64.08,56.92 65,56.01 65,54.88C65,53.76 64.08,52.85 62.94,52.85C61.8,52.85 60.88,53.76 60.88,54.88C60.88,56.01 61.8,56.92 62.94,56.92ZM45.06,56.92C46.2,56.92 47.13,56.01 47.13,54.88C47.13,53.76 46.2,52.85 45.06,52.85C43.92,52.85 43,53.76 43,54.88C43,56.01 43.92,56.92 45.06,56.92Z" | |
| 32 | + android:strokeColor="#00000000" | |
| 33 | + android:strokeWidth="1" /> | |
| 34 | +</vector> | ... | ... |
app/src/main/res/drawable/ic_launcher_background.xml
0 → 100644
| 1 | +++ a/app/src/main/res/drawable/ic_launcher_background.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<vector xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + android:width="108dp" | |
| 4 | + android:height="108dp" | |
| 5 | + android:viewportHeight="108" | |
| 6 | + android:viewportWidth="108"> | |
| 7 | + <path | |
| 8 | + android:fillColor="#26A69A" | |
| 9 | + android:pathData="M0,0h108v108h-108z" /> | |
| 10 | + <path | |
| 11 | + android:fillColor="#00000000" | |
| 12 | + android:pathData="M9,0L9,108" | |
| 13 | + android:strokeColor="#33FFFFFF" | |
| 14 | + android:strokeWidth="0.8" /> | |
| 15 | + <path | |
| 16 | + android:fillColor="#00000000" | |
| 17 | + android:pathData="M19,0L19,108" | |
| 18 | + android:strokeColor="#33FFFFFF" | |
| 19 | + android:strokeWidth="0.8" /> | |
| 20 | + <path | |
| 21 | + android:fillColor="#00000000" | |
| 22 | + android:pathData="M29,0L29,108" | |
| 23 | + android:strokeColor="#33FFFFFF" | |
| 24 | + android:strokeWidth="0.8" /> | |
| 25 | + <path | |
| 26 | + android:fillColor="#00000000" | |
| 27 | + android:pathData="M39,0L39,108" | |
| 28 | + android:strokeColor="#33FFFFFF" | |
| 29 | + android:strokeWidth="0.8" /> | |
| 30 | + <path | |
| 31 | + android:fillColor="#00000000" | |
| 32 | + android:pathData="M49,0L49,108" | |
| 33 | + android:strokeColor="#33FFFFFF" | |
| 34 | + android:strokeWidth="0.8" /> | |
| 35 | + <path | |
| 36 | + android:fillColor="#00000000" | |
| 37 | + android:pathData="M59,0L59,108" | |
| 38 | + android:strokeColor="#33FFFFFF" | |
| 39 | + android:strokeWidth="0.8" /> | |
| 40 | + <path | |
| 41 | + android:fillColor="#00000000" | |
| 42 | + android:pathData="M69,0L69,108" | |
| 43 | + android:strokeColor="#33FFFFFF" | |
| 44 | + android:strokeWidth="0.8" /> | |
| 45 | + <path | |
| 46 | + android:fillColor="#00000000" | |
| 47 | + android:pathData="M79,0L79,108" | |
| 48 | + android:strokeColor="#33FFFFFF" | |
| 49 | + android:strokeWidth="0.8" /> | |
| 50 | + <path | |
| 51 | + android:fillColor="#00000000" | |
| 52 | + android:pathData="M89,0L89,108" | |
| 53 | + android:strokeColor="#33FFFFFF" | |
| 54 | + android:strokeWidth="0.8" /> | |
| 55 | + <path | |
| 56 | + android:fillColor="#00000000" | |
| 57 | + android:pathData="M99,0L99,108" | |
| 58 | + android:strokeColor="#33FFFFFF" | |
| 59 | + android:strokeWidth="0.8" /> | |
| 60 | + <path | |
| 61 | + android:fillColor="#00000000" | |
| 62 | + android:pathData="M0,9L108,9" | |
| 63 | + android:strokeColor="#33FFFFFF" | |
| 64 | + android:strokeWidth="0.8" /> | |
| 65 | + <path | |
| 66 | + android:fillColor="#00000000" | |
| 67 | + android:pathData="M0,19L108,19" | |
| 68 | + android:strokeColor="#33FFFFFF" | |
| 69 | + android:strokeWidth="0.8" /> | |
| 70 | + <path | |
| 71 | + android:fillColor="#00000000" | |
| 72 | + android:pathData="M0,29L108,29" | |
| 73 | + android:strokeColor="#33FFFFFF" | |
| 74 | + android:strokeWidth="0.8" /> | |
| 75 | + <path | |
| 76 | + android:fillColor="#00000000" | |
| 77 | + android:pathData="M0,39L108,39" | |
| 78 | + android:strokeColor="#33FFFFFF" | |
| 79 | + android:strokeWidth="0.8" /> | |
| 80 | + <path | |
| 81 | + android:fillColor="#00000000" | |
| 82 | + android:pathData="M0,49L108,49" | |
| 83 | + android:strokeColor="#33FFFFFF" | |
| 84 | + android:strokeWidth="0.8" /> | |
| 85 | + <path | |
| 86 | + android:fillColor="#00000000" | |
| 87 | + android:pathData="M0,59L108,59" | |
| 88 | + android:strokeColor="#33FFFFFF" | |
| 89 | + android:strokeWidth="0.8" /> | |
| 90 | + <path | |
| 91 | + android:fillColor="#00000000" | |
| 92 | + android:pathData="M0,69L108,69" | |
| 93 | + android:strokeColor="#33FFFFFF" | |
| 94 | + android:strokeWidth="0.8" /> | |
| 95 | + <path | |
| 96 | + android:fillColor="#00000000" | |
| 97 | + android:pathData="M0,79L108,79" | |
| 98 | + android:strokeColor="#33FFFFFF" | |
| 99 | + android:strokeWidth="0.8" /> | |
| 100 | + <path | |
| 101 | + android:fillColor="#00000000" | |
| 102 | + android:pathData="M0,89L108,89" | |
| 103 | + android:strokeColor="#33FFFFFF" | |
| 104 | + android:strokeWidth="0.8" /> | |
| 105 | + <path | |
| 106 | + android:fillColor="#00000000" | |
| 107 | + android:pathData="M0,99L108,99" | |
| 108 | + android:strokeColor="#33FFFFFF" | |
| 109 | + android:strokeWidth="0.8" /> | |
| 110 | + <path | |
| 111 | + android:fillColor="#00000000" | |
| 112 | + android:pathData="M19,29L89,29" | |
| 113 | + android:strokeColor="#33FFFFFF" | |
| 114 | + android:strokeWidth="0.8" /> | |
| 115 | + <path | |
| 116 | + android:fillColor="#00000000" | |
| 117 | + android:pathData="M19,39L89,39" | |
| 118 | + android:strokeColor="#33FFFFFF" | |
| 119 | + android:strokeWidth="0.8" /> | |
| 120 | + <path | |
| 121 | + android:fillColor="#00000000" | |
| 122 | + android:pathData="M19,49L89,49" | |
| 123 | + android:strokeColor="#33FFFFFF" | |
| 124 | + android:strokeWidth="0.8" /> | |
| 125 | + <path | |
| 126 | + android:fillColor="#00000000" | |
| 127 | + android:pathData="M19,59L89,59" | |
| 128 | + android:strokeColor="#33FFFFFF" | |
| 129 | + android:strokeWidth="0.8" /> | |
| 130 | + <path | |
| 131 | + android:fillColor="#00000000" | |
| 132 | + android:pathData="M19,69L89,69" | |
| 133 | + android:strokeColor="#33FFFFFF" | |
| 134 | + android:strokeWidth="0.8" /> | |
| 135 | + <path | |
| 136 | + android:fillColor="#00000000" | |
| 137 | + android:pathData="M19,79L89,79" | |
| 138 | + android:strokeColor="#33FFFFFF" | |
| 139 | + android:strokeWidth="0.8" /> | |
| 140 | + <path | |
| 141 | + android:fillColor="#00000000" | |
| 142 | + android:pathData="M29,19L29,89" | |
| 143 | + android:strokeColor="#33FFFFFF" | |
| 144 | + android:strokeWidth="0.8" /> | |
| 145 | + <path | |
| 146 | + android:fillColor="#00000000" | |
| 147 | + android:pathData="M39,19L39,89" | |
| 148 | + android:strokeColor="#33FFFFFF" | |
| 149 | + android:strokeWidth="0.8" /> | |
| 150 | + <path | |
| 151 | + android:fillColor="#00000000" | |
| 152 | + android:pathData="M49,19L49,89" | |
| 153 | + android:strokeColor="#33FFFFFF" | |
| 154 | + android:strokeWidth="0.8" /> | |
| 155 | + <path | |
| 156 | + android:fillColor="#00000000" | |
| 157 | + android:pathData="M59,19L59,89" | |
| 158 | + android:strokeColor="#33FFFFFF" | |
| 159 | + android:strokeWidth="0.8" /> | |
| 160 | + <path | |
| 161 | + android:fillColor="#00000000" | |
| 162 | + android:pathData="M69,19L69,89" | |
| 163 | + android:strokeColor="#33FFFFFF" | |
| 164 | + android:strokeWidth="0.8" /> | |
| 165 | + <path | |
| 166 | + android:fillColor="#00000000" | |
| 167 | + android:pathData="M79,19L79,89" | |
| 168 | + android:strokeColor="#33FFFFFF" | |
| 169 | + android:strokeWidth="0.8" /> | |
| 170 | +</vector> | ... | ... |
app/src/main/res/layout/activity_main.xml
0 → 100644
| 1 | +++ a/app/src/main/res/layout/activity_main.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + xmlns:app="http://schemas.android.com/apk/res-auto" | |
| 4 | + xmlns:tools="http://schemas.android.com/tools" | |
| 5 | + android:layout_width="match_parent" | |
| 6 | + android:layout_height="match_parent" | |
| 7 | + android:orientation="vertical" | |
| 8 | + tools:context=".MainActivity"> | |
| 9 | + | |
| 10 | + <Button | |
| 11 | + android:layout_width="wrap_content" | |
| 12 | + android:layout_height="wrap_content" | |
| 13 | + android:text="单个下载" | |
| 14 | + android:onClick="singleDownload" | |
| 15 | + android:layout_marginTop="20dp" | |
| 16 | + android:visibility="gone"/> | |
| 17 | + | |
| 18 | + <Button | |
| 19 | + android:layout_width="wrap_content" | |
| 20 | + android:layout_height="wrap_content" | |
| 21 | + android:text="多文件下载" | |
| 22 | + android:onClick="multipleDownload" | |
| 23 | + android:layout_marginTop="20dp" | |
| 24 | + android:visibility="gone"/> | |
| 25 | + | |
| 26 | + <Button | |
| 27 | + android:layout_width="wrap_content" | |
| 28 | + android:layout_height="wrap_content" | |
| 29 | + android:text="下载" | |
| 30 | + android:onClick="limitDownload" | |
| 31 | + android:layout_marginTop="20dp" /> | |
| 32 | + | |
| 33 | + <android.support.v7.widget.RecyclerView | |
| 34 | + android:id="@+id/file_recycle" | |
| 35 | + android:layout_width="match_parent" | |
| 36 | + android:layout_height="match_parent" | |
| 37 | + android:visibility="gone" | |
| 38 | + /> | |
| 39 | + | |
| 40 | + <Button | |
| 41 | + android:layout_width="wrap_content" | |
| 42 | + android:layout_height="wrap_content" | |
| 43 | + android:text="添加1" | |
| 44 | + android:onClick="addDownload" | |
| 45 | + android:layout_marginTop="20dp"/> | |
| 46 | + | |
| 47 | + <Button | |
| 48 | + android:layout_width="wrap_content" | |
| 49 | + android:layout_height="wrap_content" | |
| 50 | + android:text="添加2" | |
| 51 | + android:onClick="multipleDownload" | |
| 52 | + android:layout_marginTop="20dp"/> | |
| 53 | + | |
| 54 | +</LinearLayout> | |
| 0 | 55 | \ No newline at end of file | ... | ... |
app/src/main/res/layout/activity_recycler.xml
0 → 100644
| 1 | +++ a/app/src/main/res/layout/activity_recycler.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + android:layout_width="match_parent" | |
| 4 | + android:layout_height="match_parent" | |
| 5 | + android:orientation="vertical"> | |
| 6 | + | |
| 7 | + <LinearLayout | |
| 8 | + android:layout_width="match_parent" | |
| 9 | + android:layout_height="wrap_content" | |
| 10 | + android:weightSum="2"> | |
| 11 | + | |
| 12 | + <Button | |
| 13 | + android:id="@+id/start_pause" | |
| 14 | + android:layout_width="wrap_content" | |
| 15 | + android:layout_height="wrap_content" | |
| 16 | + android:layout_weight="1" | |
| 17 | + android:text="全部暂停" /> | |
| 18 | + | |
| 19 | + <Button | |
| 20 | + android:id="@+id/clear" | |
| 21 | + android:layout_width="wrap_content" | |
| 22 | + android:layout_height="wrap_content" | |
| 23 | + android:layout_weight="1" | |
| 24 | + android:text="一键清空" /> | |
| 25 | + </LinearLayout> | |
| 26 | + | |
| 27 | + <android.support.v7.widget.RecyclerView | |
| 28 | + android:id="@+id/recycler_view" | |
| 29 | + android:layout_width="match_parent" | |
| 30 | + android:layout_height="match_parent"> | |
| 31 | + | |
| 32 | + </android.support.v7.widget.RecyclerView> | |
| 33 | + | |
| 34 | +</LinearLayout> | |
| 0 | 35 | \ No newline at end of file | ... | ... |
app/src/main/res/layout/activity_single.xml
0 → 100644
| 1 | +++ a/app/src/main/res/layout/activity_single.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |
| 3 | + android:layout_width="match_parent" | |
| 4 | + android:layout_height="match_parent" | |
| 5 | + xmlns:app="http://schemas.android.com/apk/res-auto"> | |
| 6 | + | |
| 7 | + <ProgressBar | |
| 8 | + android:id="@+id/main_progress" | |
| 9 | + android:layout_width="match_parent" | |
| 10 | + android:layout_height="wrap_content" | |
| 11 | + app:layout_constraintTop_toTopOf="parent" | |
| 12 | + android:layout_marginTop="10dp" | |
| 13 | + android:max="10000" | |
| 14 | + style="@style/Widget.AppCompat.ProgressBar.Horizontal" /> | |
| 15 | + | |
| 16 | + <Button | |
| 17 | + android:id="@+id/main_btn_down" | |
| 18 | + android:layout_width="wrap_content" | |
| 19 | + android:layout_height="wrap_content" | |
| 20 | + android:text="下载" | |
| 21 | + app:layout_constraintTop_toBottomOf="@+id/main_progress" | |
| 22 | + android:layout_marginTop="10dp" | |
| 23 | + app:layout_constraintRight_toLeftOf="@+id/main_btn_pause" | |
| 24 | + android:layout_marginRight="20dp"/> | |
| 25 | + | |
| 26 | + <Button | |
| 27 | + android:id="@+id/main_btn_pause" | |
| 28 | + android:layout_width="wrap_content" | |
| 29 | + android:layout_height="wrap_content" | |
| 30 | + android:text="暂停" | |
| 31 | + android:layout_marginLeft="20dp" | |
| 32 | + app:layout_constraintBaseline_toBaselineOf="@+id/main_btn_down" | |
| 33 | + app:layout_constraintRight_toLeftOf="@+id/main_btn_cancel" | |
| 34 | + android:layout_marginRight="10dp"/> | |
| 35 | + | |
| 36 | + <Button | |
| 37 | + android:id="@+id/main_btn_cancel" | |
| 38 | + android:layout_width="wrap_content" | |
| 39 | + android:layout_height="wrap_content" | |
| 40 | + android:text="取消" | |
| 41 | + android:layout_marginLeft="20dp" | |
| 42 | + app:layout_constraintBaseline_toBaselineOf="@+id/main_btn_down" | |
| 43 | + app:layout_constraintRight_toRightOf="parent" | |
| 44 | + android:layout_marginRight="10dp"/> | |
| 45 | + | |
| 46 | +</android.support.constraint.ConstraintLayout> | |
| 0 | 47 | \ No newline at end of file | ... | ... |
app/src/main/res/layout/item_download_layout.xml
0 → 100644
| 1 | +++ a/app/src/main/res/layout/item_download_layout.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<RelativeLayout | |
| 3 | + xmlns:android="http://schemas.android.com/apk/res/android" | |
| 4 | + android:layout_width="match_parent" | |
| 5 | + android:layout_height="wrap_content"> | |
| 6 | + | |
| 7 | + <LinearLayout | |
| 8 | + android:layout_width="match_parent" | |
| 9 | + android:layout_height="wrap_content" | |
| 10 | + android:gravity="center_vertical" | |
| 11 | + android:orientation="vertical"> | |
| 12 | + | |
| 13 | + <ProgressBar | |
| 14 | + android:id="@+id/main_progress" | |
| 15 | + android:layout_width="match_parent" | |
| 16 | + android:layout_height="wrap_content" | |
| 17 | + android:layout_marginTop="10dp" | |
| 18 | + android:max="10000" | |
| 19 | + style="@style/Widget.AppCompat.ProgressBar.Horizontal" /> | |
| 20 | + | |
| 21 | + <LinearLayout | |
| 22 | + android:layout_width="wrap_content" | |
| 23 | + android:layout_height="match_parent" | |
| 24 | + android:orientation="horizontal" | |
| 25 | + android:layout_marginTop="10dp" | |
| 26 | + android:layout_marginBottom="10dp" | |
| 27 | + android:layout_gravity="right"> | |
| 28 | + <Button | |
| 29 | + android:id="@+id/main_btn_down" | |
| 30 | + android:layout_width="wrap_content" | |
| 31 | + android:layout_height="wrap_content" | |
| 32 | + android:text="下载"/> | |
| 33 | + <TextView | |
| 34 | + android:id="@+id/name" | |
| 35 | + android:layout_width="50dp" | |
| 36 | + android:layout_height="wrap_content" | |
| 37 | + android:layout_gravity="center" | |
| 38 | + android:layout_marginLeft="20dp"/> | |
| 39 | + | |
| 40 | + <Button | |
| 41 | + android:id="@+id/main_btn_cancel" | |
| 42 | + android:layout_width="wrap_content" | |
| 43 | + android:layout_height="wrap_content" | |
| 44 | + android:text="取消" | |
| 45 | + android:layout_marginLeft="20dp"/> | |
| 46 | + | |
| 47 | + </LinearLayout> | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + </LinearLayout> | |
| 52 | + | |
| 53 | +</RelativeLayout> | |
| 0 | 54 | \ No newline at end of file | ... | ... |
app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
0 → 100644
| 1 | +++ a/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | |
| 3 | + <background android:drawable="@drawable/ic_launcher_background" /> | |
| 4 | + <foreground android:drawable="@drawable/ic_launcher_foreground" /> | |
| 5 | +</adaptive-icon> | |
| 0 | 6 | \ No newline at end of file | ... | ... |
app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
0 → 100644
| 1 | +++ a/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android"> | |
| 3 | + <background android:drawable="@drawable/ic_launcher_background" /> | |
| 4 | + <foreground android:drawable="@drawable/ic_launcher_foreground" /> | |
| 5 | +</adaptive-icon> | |
| 0 | 6 | \ No newline at end of file | ... | ... |
app/src/main/res/mipmap-hdpi/ic_launcher.png
0 → 100644
2.98 KB
app/src/main/res/mipmap-hdpi/ic_launcher_round.png
0 → 100644
4.91 KB
app/src/main/res/mipmap-mdpi/ic_launcher.png
0 → 100644
2.05 KB
app/src/main/res/mipmap-mdpi/ic_launcher_round.png
0 → 100644
2.79 KB
app/src/main/res/mipmap-xhdpi/ic_launcher.png
0 → 100644
4.46 KB
app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
0 → 100644
6.93 KB
app/src/main/res/mipmap-xxhdpi/ic_launcher.png
0 → 100644
6.31 KB
app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
0 → 100644
10.4 KB
app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
0 → 100644
9.03 KB
app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
0 → 100644
15.2 KB
app/src/main/res/values/colors.xml
0 → 100644
| 1 | +++ a/app/src/main/res/values/colors.xml | |
| 1 | +<?xml version="1.0" encoding="utf-8"?> | |
| 2 | +<resources> | |
| 3 | + <color name="colorPrimary">#3F51B5</color> | |
| 4 | + <color name="colorPrimaryDark">#303F9F</color> | |
| 5 | + <color name="colorAccent">#FF4081</color> | |
| 6 | + <color name="white">#ffffff</color> | |
| 7 | +</resources> | ... | ... |
app/src/main/res/values/strings.xml
0 → 100644
app/src/main/res/values/styles.xml
0 → 100644
| 1 | +++ a/app/src/main/res/values/styles.xml | |
| 1 | +<resources> | |
| 2 | + | |
| 3 | + <!-- Base application theme. --> | |
| 4 | + <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> | |
| 5 | + <!-- Customize your theme here. --> | |
| 6 | + <item name="colorPrimary">@color/colorPrimary</item> | |
| 7 | + <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | |
| 8 | + <item name="colorAccent">@color/colorAccent</item> | |
| 9 | + </style> | |
| 10 | + | |
| 11 | +</resources> | ... | ... |
build.gradle
0 → 100644
| 1 | +++ a/build.gradle | |
| 1 | +// Top-level build file where you can add configuration options common to all sub-projects/modules. | |
| 2 | + | |
| 3 | +buildscript { | |
| 4 | + | |
| 5 | + repositories { | |
| 6 | + google() | |
| 7 | + jcenter() | |
| 8 | + } | |
| 9 | + dependencies { | |
| 10 | + classpath 'com.android.tools.build:gradle:3.3.1' | |
| 11 | + classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' | |
| 12 | + | |
| 13 | + // NOTE: Do not place your application dependencies here; they belong | |
| 14 | + // in the individual module build.gradle files | |
| 15 | + } | |
| 16 | +} | |
| 17 | + | |
| 18 | +allprojects { | |
| 19 | + repositories { | |
| 20 | + google() | |
| 21 | + jcenter() | |
| 22 | + } | |
| 23 | +} | |
| 24 | + | |
| 25 | +task clean(type: Delete) { | |
| 26 | + delete rootProject.buildDir | |
| 27 | +} | ... | ... |
gradle.properties
0 → 100644
| 1 | +++ a/gradle.properties | |
| 1 | +# Project-wide Gradle settings. | |
| 2 | +# IDE (e.g. Android Studio) users: | |
| 3 | +# Gradle settings configured through the IDE *will override* | |
| 4 | +# any settings specified in this file. | |
| 5 | +# For more details on how to configure your build environment visit | |
| 6 | +# http://www.gradle.org/docs/current/userguide/build_environment.html | |
| 7 | +# Specifies the JVM arguments used for the daemon process. | |
| 8 | +# The setting is particularly useful for tweaking memory settings. | |
| 9 | +org.gradle.jvmargs=-Xmx1536m | |
| 10 | +# When configured, Gradle will run in incubating parallel mode. | |
| 11 | +# This option should only be used with decoupled projects. More details, visit | |
| 12 | +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects | |
| 13 | +# org.gradle.parallel=true | ... | ... |
gradle/wrapper/gradle-wrapper.jar
0 → 100644
No preview for this file type
gradle/wrapper/gradle-wrapper.properties
0 → 100644
| 1 | +++ a/gradle/wrapper/gradle-wrapper.properties | |
| 1 | +#Fri Apr 19 09:44:35 CST 2019 | |
| 2 | +distributionBase=GRADLE_USER_HOME | |
| 3 | +distributionPath=wrapper/dists | |
| 4 | +zipStoreBase=GRADLE_USER_HOME | |
| 5 | +zipStorePath=wrapper/dists | |
| 6 | +distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip | ... | ... |
gradlew
0 → 100644
| 1 | +++ a/gradlew | |
| 1 | +#!/usr/bin/env sh | |
| 2 | + | |
| 3 | +############################################################################## | |
| 4 | +## | |
| 5 | +## Gradle start up script for UN*X | |
| 6 | +## | |
| 7 | +############################################################################## | |
| 8 | + | |
| 9 | +# Attempt to set APP_HOME | |
| 10 | +# Resolve links: $0 may be a link | |
| 11 | +PRG="$0" | |
| 12 | +# Need this for relative symlinks. | |
| 13 | +while [ -h "$PRG" ] ; do | |
| 14 | + ls=`ls -ld "$PRG"` | |
| 15 | + link=`expr "$ls" : '.*-> \(.*\)$'` | |
| 16 | + if expr "$link" : '/.*' > /dev/null; then | |
| 17 | + PRG="$link" | |
| 18 | + else | |
| 19 | + PRG=`dirname "$PRG"`"/$link" | |
| 20 | + fi | |
| 21 | +done | |
| 22 | +SAVED="`pwd`" | |
| 23 | +cd "`dirname \"$PRG\"`/" >/dev/null | |
| 24 | +APP_HOME="`pwd -P`" | |
| 25 | +cd "$SAVED" >/dev/null | |
| 26 | + | |
| 27 | +APP_NAME="Gradle" | |
| 28 | +APP_BASE_NAME=`basename "$0"` | |
| 29 | + | |
| 30 | +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |
| 31 | +DEFAULT_JVM_OPTS="" | |
| 32 | + | |
| 33 | +# Use the maximum available, or set MAX_FD != -1 to use that value. | |
| 34 | +MAX_FD="maximum" | |
| 35 | + | |
| 36 | +warn () { | |
| 37 | + echo "$*" | |
| 38 | +} | |
| 39 | + | |
| 40 | +die () { | |
| 41 | + echo | |
| 42 | + echo "$*" | |
| 43 | + echo | |
| 44 | + exit 1 | |
| 45 | +} | |
| 46 | + | |
| 47 | +# OS specific support (must be 'true' or 'false'). | |
| 48 | +cygwin=false | |
| 49 | +msys=false | |
| 50 | +darwin=false | |
| 51 | +nonstop=false | |
| 52 | +case "`uname`" in | |
| 53 | + CYGWIN* ) | |
| 54 | + cygwin=true | |
| 55 | + ;; | |
| 56 | + Darwin* ) | |
| 57 | + darwin=true | |
| 58 | + ;; | |
| 59 | + MINGW* ) | |
| 60 | + msys=true | |
| 61 | + ;; | |
| 62 | + NONSTOP* ) | |
| 63 | + nonstop=true | |
| 64 | + ;; | |
| 65 | +esac | |
| 66 | + | |
| 67 | +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar | |
| 68 | + | |
| 69 | +# Determine the Java command to use to start the JVM. | |
| 70 | +if [ -n "$JAVA_HOME" ] ; then | |
| 71 | + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then | |
| 72 | + # IBM's JDK on AIX uses strange locations for the executables | |
| 73 | + JAVACMD="$JAVA_HOME/jre/sh/java" | |
| 74 | + else | |
| 75 | + JAVACMD="$JAVA_HOME/bin/java" | |
| 76 | + fi | |
| 77 | + if [ ! -x "$JAVACMD" ] ; then | |
| 78 | + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME | |
| 79 | + | |
| 80 | +Please set the JAVA_HOME variable in your environment to match the | |
| 81 | +location of your Java installation." | |
| 82 | + fi | |
| 83 | +else | |
| 84 | + JAVACMD="java" | |
| 85 | + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |
| 86 | + | |
| 87 | +Please set the JAVA_HOME variable in your environment to match the | |
| 88 | +location of your Java installation." | |
| 89 | +fi | |
| 90 | + | |
| 91 | +# Increase the maximum file descriptors if we can. | |
| 92 | +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then | |
| 93 | + MAX_FD_LIMIT=`ulimit -H -n` | |
| 94 | + if [ $? -eq 0 ] ; then | |
| 95 | + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then | |
| 96 | + MAX_FD="$MAX_FD_LIMIT" | |
| 97 | + fi | |
| 98 | + ulimit -n $MAX_FD | |
| 99 | + if [ $? -ne 0 ] ; then | |
| 100 | + warn "Could not set maximum file descriptor limit: $MAX_FD" | |
| 101 | + fi | |
| 102 | + else | |
| 103 | + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" | |
| 104 | + fi | |
| 105 | +fi | |
| 106 | + | |
| 107 | +# For Darwin, add options to specify how the application appears in the dock | |
| 108 | +if $darwin; then | |
| 109 | + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" | |
| 110 | +fi | |
| 111 | + | |
| 112 | +# For Cygwin, switch paths to Windows format before running java | |
| 113 | +if $cygwin ; then | |
| 114 | + APP_HOME=`cygpath --path --mixed "$APP_HOME"` | |
| 115 | + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` | |
| 116 | + JAVACMD=`cygpath --unix "$JAVACMD"` | |
| 117 | + | |
| 118 | + # We build the pattern for arguments to be converted via cygpath | |
| 119 | + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` | |
| 120 | + SEP="" | |
| 121 | + for dir in $ROOTDIRSRAW ; do | |
| 122 | + ROOTDIRS="$ROOTDIRS$SEP$dir" | |
| 123 | + SEP="|" | |
| 124 | + done | |
| 125 | + OURCYGPATTERN="(^($ROOTDIRS))" | |
| 126 | + # Add a user-defined pattern to the cygpath arguments | |
| 127 | + if [ "$GRADLE_CYGPATTERN" != "" ] ; then | |
| 128 | + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" | |
| 129 | + fi | |
| 130 | + # Now convert the arguments - kludge to limit ourselves to /bin/sh | |
| 131 | + i=0 | |
| 132 | + for arg in "$@" ; do | |
| 133 | + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` | |
| 134 | + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option | |
| 135 | + | |
| 136 | + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition | |
| 137 | + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` | |
| 138 | + else | |
| 139 | + eval `echo args$i`="\"$arg\"" | |
| 140 | + fi | |
| 141 | + i=$((i+1)) | |
| 142 | + done | |
| 143 | + case $i in | |
| 144 | + (0) set -- ;; | |
| 145 | + (1) set -- "$args0" ;; | |
| 146 | + (2) set -- "$args0" "$args1" ;; | |
| 147 | + (3) set -- "$args0" "$args1" "$args2" ;; | |
| 148 | + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; | |
| 149 | + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; | |
| 150 | + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; | |
| 151 | + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; | |
| 152 | + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; | |
| 153 | + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; | |
| 154 | + esac | |
| 155 | +fi | |
| 156 | + | |
| 157 | +# Escape application args | |
| 158 | +save () { | |
| 159 | + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done | |
| 160 | + echo " " | |
| 161 | +} | |
| 162 | +APP_ARGS=$(save "$@") | |
| 163 | + | |
| 164 | +# Collect all arguments for the java command, following the shell quoting and substitution rules | |
| 165 | +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" | |
| 166 | + | |
| 167 | +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong | |
| 168 | +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then | |
| 169 | + cd "$(dirname "$0")" | |
| 170 | +fi | |
| 171 | + | |
| 172 | +exec "$JAVACMD" "$@" | ... | ... |
gradlew.bat
0 → 100644
| 1 | +++ a/gradlew.bat | |
| 1 | +@if "%DEBUG%" == "" @echo off | |
| 2 | +@rem ########################################################################## | |
| 3 | +@rem | |
| 4 | +@rem Gradle startup script for Windows | |
| 5 | +@rem | |
| 6 | +@rem ########################################################################## | |
| 7 | + | |
| 8 | +@rem Set local scope for the variables with windows NT shell | |
| 9 | +if "%OS%"=="Windows_NT" setlocal | |
| 10 | + | |
| 11 | +set DIRNAME=%~dp0 | |
| 12 | +if "%DIRNAME%" == "" set DIRNAME=. | |
| 13 | +set APP_BASE_NAME=%~n0 | |
| 14 | +set APP_HOME=%DIRNAME% | |
| 15 | + | |
| 16 | +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | |
| 17 | +set DEFAULT_JVM_OPTS= | |
| 18 | + | |
| 19 | +@rem Find java.exe | |
| 20 | +if defined JAVA_HOME goto findJavaFromJavaHome | |
| 21 | + | |
| 22 | +set JAVA_EXE=java.exe | |
| 23 | +%JAVA_EXE% -version >NUL 2>&1 | |
| 24 | +if "%ERRORLEVEL%" == "0" goto init | |
| 25 | + | |
| 26 | +echo. | |
| 27 | +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. | |
| 28 | +echo. | |
| 29 | +echo Please set the JAVA_HOME variable in your environment to match the | |
| 30 | +echo location of your Java installation. | |
| 31 | + | |
| 32 | +goto fail | |
| 33 | + | |
| 34 | +:findJavaFromJavaHome | |
| 35 | +set JAVA_HOME=%JAVA_HOME:"=% | |
| 36 | +set JAVA_EXE=%JAVA_HOME%/bin/java.exe | |
| 37 | + | |
| 38 | +if exist "%JAVA_EXE%" goto init | |
| 39 | + | |
| 40 | +echo. | |
| 41 | +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% | |
| 42 | +echo. | |
| 43 | +echo Please set the JAVA_HOME variable in your environment to match the | |
| 44 | +echo location of your Java installation. | |
| 45 | + | |
| 46 | +goto fail | |
| 47 | + | |
| 48 | +:init | |
| 49 | +@rem Get command-line arguments, handling Windows variants | |
| 50 | + | |
| 51 | +if not "%OS%" == "Windows_NT" goto win9xME_args | |
| 52 | + | |
| 53 | +:win9xME_args | |
| 54 | +@rem Slurp the command line arguments. | |
| 55 | +set CMD_LINE_ARGS= | |
| 56 | +set _SKIP=2 | |
| 57 | + | |
| 58 | +:win9xME_args_slurp | |
| 59 | +if "x%~1" == "x" goto execute | |
| 60 | + | |
| 61 | +set CMD_LINE_ARGS=%* | |
| 62 | + | |
| 63 | +:execute | |
| 64 | +@rem Setup the command line | |
| 65 | + | |
| 66 | +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar | |
| 67 | + | |
| 68 | +@rem Execute Gradle | |
| 69 | +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% | |
| 70 | + | |
| 71 | +:end | |
| 72 | +@rem End local scope for the variables with windows NT shell | |
| 73 | +if "%ERRORLEVEL%"=="0" goto mainEnd | |
| 74 | + | |
| 75 | +:fail | |
| 76 | +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of | |
| 77 | +rem the _cmd.exe /c_ return code! | |
| 78 | +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 | |
| 79 | +exit /b 1 | |
| 80 | + | |
| 81 | +:mainEnd | |
| 82 | +if "%OS%"=="Windows_NT" endlocal | |
| 83 | + | |
| 84 | +:omega | ... | ... |
settings.gradle
0 → 100644