├── .gitignore ├── .idea ├── compiler.xml ├── copyright │ └── profiles_settings.xml ├── gradle.xml ├── misc.xml ├── modules.xml ├── runConfigurations.xml └── vcs.xml ├── README.md ├── apk └── app-debug.apk ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yuan │ │ └── downloadmanager │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── yuan │ │ │ └── downloadmanager │ │ │ ├── DApplication.java │ │ │ ├── MainActivity.java │ │ │ ├── TestAdapter.java │ │ │ └── TestEntity.java │ └── res │ │ ├── layout │ │ ├── activity_main.xml │ │ └── list_item.xml │ │ ├── mipmap-hdpi │ │ └── ic_launcher.png │ │ ├── mipmap-mdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxhdpi │ │ └── ic_launcher.png │ │ ├── mipmap-xxxhdpi │ │ └── ic_launcher.png │ │ ├── values-w820dp │ │ └── dimens.xml │ │ └── values │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── yuan │ └── downloadmanager │ └── ExampleUnitTest.java ├── build.gradle ├── captures └── demo.gif ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── library ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── yuan │ │ └── library │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── yuan │ │ │ └── library │ │ │ └── dmanager │ │ │ ├── db │ │ │ └── DaoManager.java │ │ │ ├── download │ │ │ ├── DownloadManager.java │ │ │ ├── DownloadTask.java │ │ │ ├── DownloadTaskListener.java │ │ │ ├── TaskEntity.java │ │ │ └── TaskStatus.java │ │ │ └── utils │ │ │ ├── Constants.java │ │ │ ├── FileUtils.java │ │ │ └── IOUtils.java │ └── res │ │ └── values │ │ └── strings.xml │ └── test │ └── java │ └── com │ └── yuan │ └── library │ └── ExampleUnitTest.java ├── local.properties └── settings.gradle /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.propertiesw 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | .externalNativeBuild 9 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 18 | 19 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 19 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 46 | 47 | 48 | 49 | 50 | 1.8 51 | 52 | 57 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # DownloadManager 2 | 3 | # Introduce 4 | * 基于OkHttp实现的下载管理,支持多线程、断点续传等功能,Demo演示用的是RecyclerView,在Application里可设置任务并发等。 5 | * 实现时基本无别的臃肿代码,可以方便修改使用。 6 | 7 | 8 | # Demo 9 | [Download demo apk][1] 10 | 11 | 12 | # Screenshot 13 | ![Alt text][image-1] 14 | # Use 15 | ## Gradle 16 | 17 | ``` 18 | compile 'com.yuan.library.dmanager:downloadmanager-okhttp-release:1.1.8' 19 | ``` 20 | ## Maven 21 | 22 | ``` 23 | 24 | com.yuan.library.dmanager 25 | downloadmanager-okhttp-release 26 | 1.1.8 27 | pom 28 | 29 | ``` 30 | 31 | 32 | # Code 33 | ``` 34 | // 在Application初始化 35 | DownloadManager.getInstance().init(this, 3); 36 | 37 | // 代码中使用 38 | String taskId = String.valueOf(mListData.get(holder.getAdapterPosition()).getUrl().hashCode()); 39 | DownloadTask itemTask = mDownloadManager.getTask(taskId); 40 | DownloadManager.getInstance().add(itemTask); 41 | 42 | //下载管理具体使用,也需要对列表的adapter进行处理,具体实现请参考demo。 43 | ``` 44 | # Update 45 | v1.1.8 46 | * 修复下载地址无效或者地址为空引起的crash。 47 | 48 | v1.1.7 49 | * 修复新下载任务在连接中状态时,点击按钮crash的bug。 50 | * 添加ConnectException捕获。 51 | * 更新演示demo。 52 | 53 | v1.1.6 54 | * 修改数据库的存储为GreenDao框架。 55 | 56 | v1.1.5 57 | * 修复暂停后没有更新数据库状态。 58 | 59 | v1.1.4 60 | * 最低兼容版本到14(Android4.0) 61 | 62 | v1.1.3 63 | * 修复有任务正在下载时,取消任务有时候不能中断下载的BUG。在demo中长按某个条目,可取消一个任务。 64 | 65 | v1.1.2: 66 | * 修复多个任务同时等待,暂停某个任务时,等待队列出现错误。 67 | * 修复Demo按返回键退出程序,再次进入程序,任务还在下载时,UI不刷新问题(以后版本更新,会将下载统一下放到service中)。 68 | * 优化线程池的处理。 69 | 70 | v1.1.1: 71 | * 添加超时异常的捕获。 72 | * 可以自定义OkHttpClient,通过DownloadManager.getInstance().init(this, 3,HttpClient)添加。 73 | * 如果不设置最多下载数量,那么下载数量将根据CPU核数量来分配,并且最大线程数量限制在15个。 74 | 75 | v1.1.0: 76 | * 重构了下载管理,删除冗余代码,并添加任务失败的回调。 77 | * 修复了已知bug。 78 | 79 | # Remark 80 | 由于demo中下载地址,是在本机上搭的服务器,所以点击下载按钮不能下载。如果demo中的下载测试,请在MainActivity的getMockData方法中换成可用的地址。 81 | # Contacts 82 | mail:wenbing1007@163.com 83 | 84 | qq:11026979 85 | 86 | 87 | 88 | [1]: https://github.com/yuanwenbing/DownloadManager/raw/master/apk/app-debug.apk 89 | 90 | [image-1]: https://raw.githubusercontent.com/yuanwenbing/DownloadManager/master/captures/demo.gif "Optional title" 91 | 92 | -------------------------------------------------------------------------------- /apk/app-debug.apk: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuanwenbing/DownloadManager/42203f2cff1fc0c0820242f0401cddd4be0addbc/apk/app-debug.apk -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'android-apt' 3 | 4 | android { 5 | compileSdkVersion 24 6 | buildToolsVersion "24.0.1" 7 | defaultConfig { 8 | applicationId "com.yuan.downloadmanager" 9 | minSdkVersion 14 10 | targetSdkVersion 21 11 | versionCode 1 12 | versionName "1.1.8" 13 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 14 | } 15 | buildTypes { 16 | release { 17 | minifyEnabled false 18 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 19 | } 20 | } 21 | 22 | lintOptions { 23 | abortOnError false 24 | } 25 | 26 | } 27 | 28 | dependencies { 29 | compile fileTree(include: ['*.jar'], dir: 'libs') 30 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 31 | exclude group: 'com.android.support', module: 'support-annotations' 32 | }) 33 | compile 'com.android.support:appcompat-v7:24.1.1' 34 | testCompile 'junit:junit:4.12' 35 | compile project(':library') 36 | compile 'com.jakewharton:butterknife:8.4.0' 37 | apt 'com.jakewharton:butterknife-compiler:8.4.0' 38 | compile 'com.android.support:recyclerview-v7:24.1.1' 39 | compile 'com.android.support:cardview-v7:24.1.1' 40 | } 41 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/Yuan/Work/adt-bundle-mac/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /app/src/androidTest/java/com/yuan/downloadmanager/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.yuan.downloadmanager; 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 | * Instrumentation test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() throws Exception { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.yuan.downloadmanager", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 16 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/yuan/downloadmanager/DApplication.java: -------------------------------------------------------------------------------- 1 | package com.yuan.downloadmanager; 2 | 3 | import android.app.Application; 4 | 5 | import com.yuan.library.dmanager.download.DownloadManager; 6 | 7 | /** 8 | * Created by Yuan on 27/09/2016:1:33 PM. 9 | *

10 | * Description:com.yuan.downloadmanager.DApplication 11 | */ 12 | 13 | public class DApplication extends Application { 14 | @Override 15 | public void onCreate() { 16 | super.onCreate(); 17 | DownloadManager.getInstance().init(this, 3); 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/yuan/downloadmanager/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.yuan.downloadmanager; 2 | 3 | import android.os.Bundle; 4 | import android.support.v7.app.AppCompatActivity; 5 | import android.support.v7.widget.LinearLayoutManager; 6 | import android.support.v7.widget.RecyclerView; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | import butterknife.BindView; 12 | import butterknife.ButterKnife; 13 | 14 | /** 15 | * Created by yuan 01/03/2017. 16 | */ 17 | 18 | public class MainActivity extends AppCompatActivity { 19 | @BindView(R.id.recyclerView) 20 | RecyclerView mRecyclerView; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_main); 26 | ButterKnife.bind(this); 27 | 28 | mRecyclerView.setLayoutManager(new LinearLayoutManager(this)); 29 | final TestAdapter adapter = new TestAdapter(this, getMockData()); 30 | mRecyclerView.setAdapter(adapter); 31 | 32 | } 33 | 34 | private List getMockData() { 35 | List list = new ArrayList<>(); 36 | 37 | for (int i = 0; i < 18; i++) { 38 | TestEntity entity = new TestEntity(); 39 | entity.setTitle(i + ""); 40 | entity.setUrl("http://192.168.1.94:8888/test" + i + ".dmg"); 41 | list.add(entity); 42 | } 43 | 44 | return list; 45 | 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /app/src/main/java/com/yuan/downloadmanager/TestAdapter.java: -------------------------------------------------------------------------------- 1 | package com.yuan.downloadmanager; 2 | 3 | import android.content.Context; 4 | import android.support.annotation.NonNull; 5 | import android.support.v7.widget.RecyclerView; 6 | import android.text.TextUtils; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.Button; 11 | import android.widget.ProgressBar; 12 | import android.widget.TextView; 13 | import android.widget.Toast; 14 | 15 | import com.yuan.library.dmanager.download.DownloadManager; 16 | import com.yuan.library.dmanager.download.DownloadTask; 17 | import com.yuan.library.dmanager.download.DownloadTaskListener; 18 | import com.yuan.library.dmanager.download.TaskEntity; 19 | 20 | import java.text.DecimalFormat; 21 | import java.util.List; 22 | 23 | import butterknife.BindView; 24 | import butterknife.ButterKnife; 25 | 26 | import static com.yuan.library.dmanager.download.TaskStatus.TASK_STATUS_CANCEL; 27 | import static com.yuan.library.dmanager.download.TaskStatus.TASK_STATUS_CONNECTING; 28 | import static com.yuan.library.dmanager.download.TaskStatus.TASK_STATUS_DOWNLOADING; 29 | import static com.yuan.library.dmanager.download.TaskStatus.TASK_STATUS_FINISH; 30 | import static com.yuan.library.dmanager.download.TaskStatus.TASK_STATUS_INIT; 31 | import static com.yuan.library.dmanager.download.TaskStatus.TASK_STATUS_PAUSE; 32 | import static com.yuan.library.dmanager.download.TaskStatus.TASK_STATUS_QUEUE; 33 | import static com.yuan.library.dmanager.download.TaskStatus.TASK_STATUS_REQUEST_ERROR; 34 | import static com.yuan.library.dmanager.download.TaskStatus.TASK_STATUS_STORAGE_ERROR; 35 | 36 | /** 37 | * Created by Yuan on 9/19/16:2:31 PM. 38 | *

39 | * Description:com.yuan.downloadmanager.ListAdapter 40 | */ 41 | 42 | class TestAdapter extends RecyclerView.Adapter { 43 | 44 | private Context mContext; 45 | 46 | private List mListData; 47 | 48 | private DownloadManager mDownloadManager; 49 | 50 | TestAdapter(Context context, List list) { 51 | mContext = context; 52 | mListData = list; 53 | mDownloadManager = DownloadManager.getInstance(); 54 | } 55 | 56 | @Override 57 | public CViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { 58 | View itemView = LayoutInflater.from(mContext).inflate(R.layout.list_item, parent, false); 59 | return new CViewHolder(itemView); 60 | } 61 | 62 | @Override 63 | public void onBindViewHolder(final CViewHolder holder, final int position) { 64 | 65 | final TestEntity entity = mListData.get(holder.getAdapterPosition()); 66 | holder.titleView.setText(entity.getTitle()); 67 | 68 | if(TextUtils.isEmpty( entity.getUrl())){ 69 | entity.setUrl("the item of " + holder.getAdapterPosition() + " is empty url..."); 70 | } 71 | holder.itemView.setTag(entity.getUrl()); 72 | String taskId = String.valueOf(entity.getUrl().hashCode()); 73 | DownloadTask itemTask = mDownloadManager.getTask(taskId); 74 | 75 | if (itemTask == null) { 76 | holder.downloadButton.setText(R.string.start); 77 | holder.progressView.setText("0"); 78 | holder.progressBar.setProgress(0); 79 | } else { 80 | TaskEntity taskEntity = itemTask.getTaskEntity(); 81 | int status = taskEntity.getTaskStatus(); 82 | responseUIListener(itemTask, holder); 83 | String progress = getPercent(taskEntity.getCompletedSize(), taskEntity.getTotalSize()); 84 | switch (status) { 85 | case TASK_STATUS_INIT: 86 | boolean isPause = mDownloadManager.isPauseTask(taskEntity.getTaskId()); 87 | boolean isFinish = mDownloadManager.isFinishTask(taskEntity.getTaskId()); 88 | holder.downloadButton.setText(isFinish ? R.string.delete : !isPause ? R.string.start : R.string.resume); 89 | holder.progressBar.setProgress(Integer.parseInt(progress)); 90 | holder.progressView.setText(progress); 91 | break; 92 | case TASK_STATUS_QUEUE: 93 | holder.downloadButton.setText(R.string.queue); 94 | holder.progressBar.setProgress(Integer.parseInt(progress)); 95 | holder.progressView.setText(progress); 96 | break; 97 | case TASK_STATUS_CONNECTING: 98 | holder.downloadButton.setText(R.string.connecting); 99 | holder.progressBar.setProgress(Integer.parseInt(progress)); 100 | holder.progressView.setText(progress); 101 | break; 102 | case TASK_STATUS_DOWNLOADING: 103 | holder.downloadButton.setText(R.string.pause); 104 | holder.progressBar.setProgress(Integer.parseInt(progress)); 105 | holder.progressView.setText(progress); 106 | break; 107 | case TASK_STATUS_PAUSE: 108 | holder.downloadButton.setText(R.string.resume); 109 | holder.progressBar.setProgress(Integer.parseInt(progress)); 110 | holder.progressView.setText(progress); 111 | break; 112 | case TASK_STATUS_FINISH: 113 | holder.downloadButton.setText(R.string.delete); 114 | holder.progressBar.setProgress(Integer.parseInt(progress)); 115 | holder.progressView.setText(progress); 116 | break; 117 | case TASK_STATUS_REQUEST_ERROR: 118 | holder.downloadButton.setText(R.string.retry); 119 | holder.progressBar.setProgress(Integer.parseInt(progress)); 120 | holder.progressView.setText(progress); 121 | case TASK_STATUS_STORAGE_ERROR: 122 | holder.downloadButton.setText(R.string.retry); 123 | holder.progressBar.setProgress(Integer.parseInt(progress)); 124 | holder.progressView.setText(progress); 125 | break; 126 | } 127 | } 128 | 129 | 130 | holder.downloadButton.setOnClickListener(new View.OnClickListener() { 131 | @Override 132 | public void onClick(View v) { 133 | String url = entity.getUrl(); 134 | String taskId = String.valueOf(url.hashCode()); 135 | DownloadTask itemTask = mDownloadManager.getTask(taskId); 136 | 137 | if (itemTask == null) { 138 | itemTask = new DownloadTask(new TaskEntity.Builder().url(entity.getUrl()).build()); 139 | responseUIListener(itemTask, holder); 140 | mDownloadManager.addTask(itemTask); 141 | } else { 142 | responseUIListener(itemTask, holder); 143 | TaskEntity taskEntity = itemTask.getTaskEntity(); 144 | int status = taskEntity.getTaskStatus(); 145 | switch (status) { 146 | case TASK_STATUS_QUEUE: 147 | mDownloadManager.pauseTask(itemTask); 148 | break; 149 | case TASK_STATUS_INIT: 150 | mDownloadManager.addTask(itemTask); 151 | break; 152 | case TASK_STATUS_CONNECTING: 153 | mDownloadManager.pauseTask(itemTask); 154 | break; 155 | case TASK_STATUS_DOWNLOADING: 156 | mDownloadManager.pauseTask(itemTask); 157 | break; 158 | case TASK_STATUS_CANCEL: 159 | mDownloadManager.addTask(itemTask); 160 | break; 161 | case TASK_STATUS_PAUSE: 162 | mDownloadManager.resumeTask(itemTask); 163 | break; 164 | case TASK_STATUS_FINISH: 165 | mDownloadManager.cancelTask(itemTask); 166 | break; 167 | case TASK_STATUS_REQUEST_ERROR: 168 | mDownloadManager.addTask(itemTask); 169 | break; 170 | case TASK_STATUS_STORAGE_ERROR: 171 | mDownloadManager.addTask(itemTask); 172 | break; 173 | } 174 | } 175 | } 176 | }); 177 | } 178 | 179 | 180 | private void responseUIListener(@NonNull final DownloadTask itemTask, final CViewHolder holder) { 181 | 182 | final TaskEntity taskEntity = itemTask.getTaskEntity(); 183 | 184 | itemTask.setListener(new DownloadTaskListener() { 185 | 186 | @Override 187 | public void onQueue(DownloadTask downloadTask) { 188 | if (holder.itemView.getTag().equals(taskEntity.getUrl())) { 189 | holder.downloadButton.setText(R.string.queue); 190 | } 191 | } 192 | 193 | @Override 194 | public void onConnecting(DownloadTask downloadTask) { 195 | if (holder.itemView.getTag().equals(taskEntity.getUrl())) { 196 | holder.downloadButton.setText(R.string.connecting); 197 | } 198 | } 199 | 200 | @Override 201 | public void onStart(DownloadTask downloadTask) { 202 | if (holder.itemView.getTag().equals(taskEntity.getUrl())) { 203 | holder.downloadButton.setText(R.string.pause); 204 | holder.progressBar.setProgress(Integer.parseInt(getPercent(taskEntity.getCompletedSize(), taskEntity.getTotalSize()))); 205 | holder.progressView.setText(getPercent(taskEntity.getCompletedSize(), taskEntity.getTotalSize())); 206 | } 207 | } 208 | 209 | @Override 210 | public void onPause(DownloadTask downloadTask) { 211 | if (holder.itemView.getTag().equals(taskEntity.getUrl())) { 212 | holder.downloadButton.setText(R.string.resume); 213 | } 214 | } 215 | 216 | @Override 217 | public void onCancel(DownloadTask downloadTask) { 218 | if (holder.itemView.getTag().equals(taskEntity.getUrl())) { 219 | holder.downloadButton.setText(R.string.start); 220 | holder.progressView.setText("0"); 221 | holder.progressBar.setProgress(0); 222 | } 223 | } 224 | 225 | @Override 226 | public void onFinish(DownloadTask downloadTask) { 227 | if (holder.itemView.getTag().equals(taskEntity.getUrl())) { 228 | holder.downloadButton.setText(R.string.delete); 229 | } 230 | } 231 | 232 | @Override 233 | public void onError(DownloadTask downloadTask, int codeError) { 234 | if (holder.itemView.getTag().equals(taskEntity.getUrl())) { 235 | 236 | holder.downloadButton.setText(R.string.retry); 237 | switch (codeError) { 238 | case TASK_STATUS_REQUEST_ERROR: 239 | Toast.makeText(mContext, R.string.request_error, Toast.LENGTH_SHORT).show(); 240 | break; 241 | case TASK_STATUS_STORAGE_ERROR: 242 | Toast.makeText(mContext, R.string.storage_error, Toast.LENGTH_SHORT).show(); 243 | break; 244 | 245 | } 246 | 247 | } 248 | } 249 | }); 250 | 251 | } 252 | 253 | private String getPercent(long completed, long total) { 254 | 255 | if (total > 0) { 256 | double fen = ((double) completed / (double) total) * 100; 257 | DecimalFormat df1 = new DecimalFormat("0"); 258 | return df1.format(fen); 259 | } 260 | return "0"; 261 | } 262 | 263 | @Override 264 | public int getItemCount() { 265 | return mListData.size(); 266 | } 267 | 268 | class CViewHolder extends RecyclerView.ViewHolder { 269 | 270 | @BindView(R.id.list_item_title) 271 | TextView titleView; 272 | 273 | @BindView(R.id.list_item_progress_bar) 274 | ProgressBar progressBar; 275 | 276 | @BindView(R.id.list_item_progress_text) 277 | TextView progressView; 278 | 279 | @BindView(R.id.list_item_state_button) 280 | Button downloadButton; 281 | 282 | CViewHolder(View itemView) { 283 | super(itemView); 284 | ButterKnife.bind(this, itemView); 285 | } 286 | } 287 | } 288 | -------------------------------------------------------------------------------- /app/src/main/java/com/yuan/downloadmanager/TestEntity.java: -------------------------------------------------------------------------------- 1 | package com.yuan.downloadmanager; 2 | 3 | /** 4 | * Created by Yuan on 9/19/16:2:49 PM. 5 | *

6 | * Description:com.yuan.downloadmanager.TestEntity 7 | */ 8 | 9 | public class TestEntity { 10 | 11 | private String title; 12 | private String url; 13 | 14 | public String getTitle() { 15 | return title; 16 | } 17 | 18 | public void setTitle(String title) { 19 | this.title = title; 20 | } 21 | 22 | public String getUrl() { 23 | return url; 24 | } 25 | 26 | public void setUrl(String url) { 27 | this.url = url; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/layout/list_item.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 20 | 21 | 27 | 28 | 36 | 37 | 43 | 44 |