Skip to content

Commit 40ffd55

Browse files
committed
文件下载增加协程方式
1 parent a5e64c1 commit 40ffd55

File tree

10 files changed

+481
-129
lines changed

10 files changed

+481
-129
lines changed

CHANGE_lOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
# CHANGE LOG
2+
### v0.4.2(2022.4.19)
3+
4+
+ 文件下载增加协程方式
5+
26
### v0.4.1(2022.1.14)
37

48
+ 多文件下载增加进度回调接口
Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package com.catchpig.kmvvm.apk.viewmodel
22

33
import androidx.lifecycle.MutableLiveData
4+
import androidx.lifecycle.viewModelScope
45
import com.catchpig.mvvm.base.viewmodel.BaseViewModel
56
import com.catchpig.mvvm.entity.DownloadProgress
6-
import com.catchpig.mvvm.network.manager.DownloadManager
7+
import com.catchpig.mvvm.network.manager.CoroutinesDownloadManager
8+
import com.catchpig.mvvm.network.manager.RxJavaDownloadManager
9+
import kotlinx.coroutines.Dispatchers
10+
import kotlinx.coroutines.launch
711

812
/**
913
*
@@ -17,18 +21,33 @@ class InstallApkViewModel : BaseViewModel() {
1721

1822
fun download() {
1923
val downloadUrlpng = "http://a.xzfile.com/apk4/apkwjql_v1.1_downcc.com.apk"
20-
val downloadUrlpng1 = "http://a.xzfile.com/apk4/apkpure_v3.17.32_downcc.com.apk"
24+
val downloadUrlpng1 =
25+
"https://imtt.dd.qq.com/16891/myapp/channel_102497291_1165285_b0e7c10e19b54b31dfaf1fd4c0150e44.apk?hsr=5848"
2126
val downloadUrl = "https://wanandroid.com/blogimgs/2d120094-e1ee-47fb-a155-6eb4ca49d01f.apk"
22-
DownloadManager.download(downloadUrlpng, {
27+
viewModelScope.launch(Dispatchers.Main) {
28+
// RxJavaDownloadManager.download(downloadUrlpng, {
29+
//
30+
// }, { downloadProgress ->
31+
// progressLiveData.value = downloadProgress
32+
// })
33+
//
34+
// RxJavaDownloadManager.multiDownload(listOf(downloadUrl, downloadUrlpng1), {
35+
//
36+
// }, { downloadProgress ->
37+
// progressLiveData1.value = downloadProgress
38+
// })
39+
CoroutinesDownloadManager.download(downloadUrlpng, {
2340

24-
}, { downloadProgress ->
25-
progressLiveData.value = downloadProgress
26-
})
41+
}, { downloadProgress ->
42+
progressLiveData.value = downloadProgress
43+
})
2744

28-
DownloadManager.multiDownload(listOf(downloadUrl, downloadUrlpng1), {
45+
CoroutinesDownloadManager.multiDownload(listOf(downloadUrl, downloadUrlpng1), {
46+
47+
}, { downloadProgress ->
48+
progressLiveData1.value = downloadProgress
49+
})
50+
}
2951

30-
}, { downloadProgress ->
31-
progressLiveData1.value = downloadProgress
32-
})
3352
}
3453
}

app/src/main/java/com/catchpig/kmvvm/child/ChildActivity.kt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,25 +12,25 @@ class ChildActivity : BaseVMActivity<ActivityChildBinding, ChildViewModel>() {
1212
@OnClickFirstDrawable(R.drawable.more)
1313
fun clickFirstDrawable(v: View) {
1414
snackBar("第一个图标按钮点击生效")
15-
updateTitle("nihao")
15+
updateTitle("第一图标")
1616
}
1717

1818
@OnClickFirstText(R.string.more)
1919
fun clickFirstText() {
2020
snackBar("第一个文字按钮点击生效")
21-
updateTitle("12354")
21+
updateTitle("第一文字")
2222
}
2323

2424
@OnClickSecondDrawable(R.drawable.more)
2525
fun clickSecondDrawable(v: View) {
2626
snackBar("第二个图标按钮点击生效")
27-
updateTitle("nihao")
27+
updateTitle("第二图标")
2828
}
2929

3030
@OnClickSecondText(R.string.more)
3131
fun clickSecondText() {
3232
snackBar("第二个文字按钮点击生效")
33-
updateTitle("12354")
33+
updateTitle("第二文字")
3434
}
3535

3636
override fun initParam() {

mvvm/src/main/java/com/catchpig/mvvm/network/api/DownloadService.kt renamed to mvvm/src/main/java/com/catchpig/mvvm/network/api/CoroutinesDownloadService.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
11
package com.catchpig.mvvm.network.api
22

3-
import io.reactivex.rxjava3.core.Flowable
43
import okhttp3.ResponseBody
54
import retrofit2.http.GET
65
import retrofit2.http.Streaming
76
import retrofit2.http.Url
7+
88
/**
99
* 下载网络接口服务
1010
* @author catchpig
1111
* @date 2020/11/20 10:25
1212
*/
13-
interface DownloadService {
13+
interface CoroutinesDownloadService {
1414
/**
1515
* 可以断点续传
1616
* @param url 下载地址
1717
*/
1818
@Streaming
1919
@GET
20-
fun download(@Url url:String):Flowable<ResponseBody>
20+
suspend fun download(@Url url:String):ResponseBody
2121
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.catchpig.mvvm.network.api
2+
3+
import io.reactivex.rxjava3.core.Flowable
4+
import kotlinx.coroutines.flow.Flow
5+
import okhttp3.ResponseBody
6+
import retrofit2.http.GET
7+
import retrofit2.http.Streaming
8+
import retrofit2.http.Url
9+
10+
/**
11+
* 下载网络接口服务
12+
* @author catchpig
13+
* @date 2020/11/20 10:25
14+
*/
15+
interface RxJavaDownloadService {
16+
/**
17+
* 可以断点续传
18+
* @param url 下载地址
19+
*/
20+
@Streaming
21+
@GET
22+
fun download(@Url url: String): Flowable<ResponseBody>
23+
}

mvvm/src/main/java/com/catchpig/mvvm/network/download/DownloadSubscriber.kt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,42 @@ class DownloadSubscriber(private val downloadCallback: DownloadCallback) :
2020
const val TAG = "DownloadSubscriber"
2121
}
2222

23-
override fun onStart() {
23+
public override fun onStart() {
2424
super.onStart()
25+
"onStart".logd(TAG)
2526
downloadCallback.onStart()
2627
}
2728

2829
override fun onNext(t: String) {
30+
"onNext($t)".logd(TAG)
2931
downloadCallback.onSuccess(t)
3032
}
3133

3234
override fun onError(t: Throwable?) {
3335
t?.let {
36+
if (t is Exception) {
37+
t.printStackTrace()
38+
}
39+
"onError(${it})".logd(TAG)
3440
downloadCallback.onError(it)
3541
}
3642
}
3743

3844
override fun onComplete() {
45+
"onComplete".logd(TAG)
3946
downloadCallback.onComplete()
4047
}
4148

4249
override fun update(read: Long, count: Long, done: Boolean) {
43-
Flowable.just(done).subscribeOn(AndroidSchedulers.mainThread()).subscribe(Consumer {
50+
Flowable.just(done).subscribeOn(AndroidSchedulers.mainThread()).subscribe {
4451
val downloadProgress = if (done) {
4552
DownloadProgress(read, count, 1, 1)
4653
} else {
4754
DownloadProgress(read, count, 0, 1)
4855
}
49-
"progress:$downloadProgress".logd(TAG)
56+
"update($read,$count,$done)".logd(TAG)
5057
downloadCallback.onProgress(downloadProgress)
51-
})
58+
}
5259

5360
}
5461
}

mvvm/src/main/java/com/catchpig/mvvm/network/download/MultiDownloadSubscriber.kt

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import com.catchpig.mvvm.listener.MultiDownloadCallback
66
import com.catchpig.utils.ext.logd
77
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
88
import io.reactivex.rxjava3.core.Flowable
9-
import io.reactivex.rxjava3.functions.Consumer
109
import io.reactivex.rxjava3.subscribers.ResourceSubscriber
1110

1211
/**
@@ -23,36 +22,43 @@ class MultiDownloadSubscriber(
2322
}
2423

2524
private var paths = arrayListOf<String>()
26-
override fun onStart() {
25+
public override fun onStart() {
2726
super.onStart()
27+
"onStart".logd(TAG)
2828
multiDownloadCallback.onStart()
2929
}
3030

3131
override fun onNext(t: String) {
32+
"onNext($t)".logd(TAG)
3233
paths.add(t)
3334
}
3435

3536
override fun onError(t: Throwable?) {
3637
t?.let {
38+
if (t is Exception) {
39+
t.printStackTrace()
40+
}
41+
"onError($t)".logd(TAG)
3742
multiDownloadCallback.onError(it)
3843
}
3944
}
4045

4146
override fun onComplete() {
47+
"onComplete($paths)".logd(TAG)
4248
multiDownloadCallback.onSuccess(paths)
4349
multiDownloadCallback.onComplete()
4450
}
4551

4652
override fun update(read: Long, count: Long, done: Boolean) {
47-
Flowable.just(done).subscribeOn(AndroidSchedulers.mainThread()).subscribe(Consumer {
53+
Flowable.just(done).subscribeOn(AndroidSchedulers.mainThread()).subscribe {
4854
val completeCount = paths.size
4955
val downloadProgress = if (done && (completeCount + 1) == totalCount) {
5056
DownloadProgress(read, count, totalCount, totalCount)
5157
} else {
5258
DownloadProgress(read, count, completeCount, totalCount)
5359
}
54-
"progress:$downloadProgress".logd(TAG)
60+
"update($read,$count,$done)".logd(TAG)
5561
multiDownloadCallback.onProgress(downloadProgress)
56-
})
62+
}
5763
}
5864
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
package com.catchpig.mvvm.network.manager
2+
3+
import android.os.Environment
4+
import com.catchpig.mvvm.manager.ContextManager
5+
import com.catchpig.mvvm.network.interceptor.DownloadInterceptor
6+
import okhttp3.OkHttpClient
7+
import okhttp3.ResponseBody
8+
import okhttp3.logging.HttpLoggingInterceptor
9+
import java.io.File
10+
import java.io.IOException
11+
import java.io.RandomAccessFile
12+
import java.nio.channels.FileChannel
13+
import java.util.concurrent.TimeUnit
14+
15+
open class BaseDownloadManager {
16+
companion object {
17+
/**
18+
* 连接超时时间(秒)
19+
*/
20+
private const val CONNECT_TIMEOUT = 5L
21+
22+
/**
23+
* 读取数据超时时间(分钟)
24+
*/
25+
private const val READ_TIMEOUT = 10L
26+
}
27+
28+
29+
private val logInterceptor by lazy {
30+
val httpLoggingInterceptor = HttpLoggingInterceptor()
31+
httpLoggingInterceptor.level = HttpLoggingInterceptor.Level.BODY
32+
httpLoggingInterceptor
33+
}
34+
35+
protected val downloadInterceptor by lazy {
36+
DownloadInterceptor()
37+
}
38+
39+
private var okHttpClient: OkHttpClient? = null
40+
41+
protected fun getOkHttpClient(): OkHttpClient {
42+
if (okHttpClient == null) {
43+
okHttpClient = OkHttpClient
44+
.Builder()
45+
/**
46+
* 连接超时时间5秒
47+
*/
48+
.connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS)
49+
/**
50+
* 读取数据超时时间10分钟
51+
*/
52+
.readTimeout(READ_TIMEOUT, TimeUnit.MINUTES)
53+
.addInterceptor(logInterceptor)
54+
.addInterceptor(downloadInterceptor)
55+
.build()
56+
}
57+
return okHttpClient!!
58+
}
59+
60+
/**
61+
* 生成文件的地址
62+
* @param downloadUrl String
63+
* @return String
64+
*/
65+
protected fun localFileName(downloadUrl: String): String {
66+
val fileName = downloadUrl.replace("/", "").replace("\\", "")
67+
var cashDir = getDownloadFilePath()
68+
return "$cashDir/download/$fileName"
69+
}
70+
71+
private fun getDownloadFilePath(): String {
72+
return if (Environment.MEDIA_MOUNTED == Environment.getExternalStorageState()) {
73+
//有SD卡,拿到SD卡的/storage/sdcard0/Android/data/包名/cash目录
74+
ContextManager.context.externalCacheDir!!.absolutePath
75+
} else {
76+
//没有SD卡的,拿到/data/data/包名/cash目录
77+
ContextManager.context.cacheDir.absolutePath
78+
}
79+
}
80+
81+
/**
82+
* 将下载的数据写入本地缓存
83+
* @param responseBody ResponseBody 下载的文件数据
84+
* @param fileName String 文件名称
85+
* @return String 本地路径
86+
* @throws IOException
87+
*/
88+
@Throws(IOException::class)
89+
protected fun writeCache(responseBody: ResponseBody, fileName: String): String {
90+
var file = File(fileName)
91+
if (!file.parentFile.exists()) {
92+
file.parentFile.mkdirs()
93+
} else if (file.exists()) {
94+
if (file.length() == responseBody.contentLength()) {
95+
return fileName
96+
} else {
97+
file.delete()
98+
}
99+
}
100+
var randomAccessFile = RandomAccessFile(file, "rwd")
101+
var fileChannel = randomAccessFile.channel
102+
var mappedByteBuffer =
103+
fileChannel.map(FileChannel.MapMode.READ_WRITE, 0, responseBody.contentLength())
104+
var buffer = ByteArray(1024 * 8)
105+
var len: Int
106+
while (true) {
107+
len = responseBody.byteStream().read(buffer)
108+
if (len == -1) {
109+
break
110+
}
111+
mappedByteBuffer.put(buffer, 0, len)
112+
}
113+
responseBody.byteStream().close()
114+
fileChannel?.close()
115+
randomAccessFile?.close()
116+
return fileName
117+
}
118+
}

0 commit comments

Comments
 (0)