Skip to content

Commit 2a39fcc

Browse files
committed
commit
1 parent b2b6f02 commit 2a39fcc

11 files changed

Lines changed: 175 additions & 217 deletions

File tree

app/build.gradle

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
apply plugin: 'com.android.application'
22
apply plugin: 'kotlin-android'
3-
apply plugin: 'kotlin-android-extensions'
43

54
android {
65
compileSdkVersion 28
7-
buildToolsVersion "28.0.3"
86

97
defaultConfig {
108
applicationId "zlc.season.downloadxdemo"
@@ -23,6 +21,14 @@ android {
2321
}
2422
}
2523

24+
compileOptions {
25+
sourceCompatibility 1.8
26+
targetCompatibility 1.8
27+
}
28+
29+
buildFeatures {
30+
viewBinding true
31+
}
2632
}
2733

2834
dependencies {

app/src/main/java/zlc/season/downloadxdemo/MainActivity.kt

Lines changed: 10 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,92 +1,38 @@
11
package zlc.season.downloadxdemo
22

3-
import androidx.appcompat.app.AppCompatActivity
43
import android.os.Bundle
5-
import kotlinx.android.synthetic.main.activity_main.*
4+
import androidx.appcompat.app.AppCompatActivity
65
import kotlinx.coroutines.*
76
import kotlinx.coroutines.channels.*
87
import kotlinx.coroutines.flow.*
9-
import zlc.season.downloadx.Progress
108
import zlc.season.downloadx.download
11-
import zlc.season.downloadx.utils.log
12-
import kotlin.coroutines.CoroutineContext
13-
import kotlin.coroutines.EmptyCoroutineContext
9+
import zlc.season.downloadxdemo.databinding.ActivityMainBinding
1410

1511
class MainActivity : AppCompatActivity(), CoroutineScope by MainScope() {
12+
val binding by lazy { ActivityMainBinding.inflate(layoutInflater) }
1613

17-
var i = 1
18-
var j = 0
19-
val stateFlow = MutableStateFlow(1)
2014
override fun onCreate(savedInstanceState: Bundle?) {
2115
super.onCreate(savedInstanceState)
22-
setContentView(R.layout.activity_main)
16+
setContentView(binding.root)
2317

2418
val url = "https://dldir1.qq.com/weixin/android/weixin7011android1600.apk"
2519

2620
val task = url.download(this)
2721

22+
task.progress(1000)
23+
.onEach {
24+
println(it.percentStr())
25+
}.launchIn(this@MainActivity)
2826

29-
// stateFlow
30-
// .flatMapConcat {
31-
// flow {
32-
// while (i % 8 != 0) {
33-
// emit(++i)
34-
// }
35-
// }
36-
// }
37-
// .onEach {
38-
// println(it)
39-
// }.launchIn(this)
40-
41-
button.setOnClickListener {
42-
i++
43-
stateFlow.value = j++
44-
45-
// launch {
46-
// test()
47-
// }
48-
// launch {
49-
// test1()
50-
// }
51-
task.progress(1000)
52-
.onEach {
53-
println(it.percentStr())
54-
}.launchIn(this@MainActivity)
27+
binding.button.setOnClickListener {
5528
task.start()
5629
}
5730

58-
button1.setOnClickListener {
31+
binding.button1.setOnClickListener {
5932
task.stop()
6033
}
6134
}
6235

63-
val channel = Channel<A>(10)
64-
65-
suspend fun test() {
66-
val list = mutableListOf<A>()
67-
for ((i, j) in (0 until 10).withIndex()) {
68-
list.add(A(i))
69-
}
70-
71-
list.forEach {
72-
channel.send(it)
73-
}
74-
}
75-
76-
suspend fun test1() {
77-
repeat(3) {
78-
launch {
79-
channel.consumeEach {
80-
println("A: ${it.i} handing...")
81-
delay(5000)
82-
println("A: ${it.i} handed")
83-
}
84-
}
85-
}
86-
}
87-
88-
class A(val i: Int)
89-
9036
override fun onPause() {
9137
super.onPause()
9238
cancel()

build.gradle

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.kotlin_version = '1.4.0'
4+
ext.kotlin_version = '1.4.21'
55
repositories {
66
google()
77
jcenter()
88
maven { url 'https://jitpack.io' }
99
}
1010
dependencies {
11-
classpath 'com.android.tools.build:gradle:4.0.1'
11+
classpath 'com.android.tools.build:gradle:4.1.1'
1212
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
1313

1414
// NOTE: Do not place your application dependencies here; they belong

downloadx/build.gradle

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
11
apply plugin: 'com.android.library'
22
apply plugin: 'kotlin-android'
3-
apply plugin: 'kotlin-android-extensions'
43

54
android {
65
compileSdkVersion 28
7-
buildToolsVersion "28.0.3"
86

97
defaultConfig {
108
minSdkVersion 16
@@ -23,23 +21,27 @@ android {
2321
}
2422
}
2523

24+
compileOptions {
25+
sourceCompatibility 1.8
26+
targetCompatibility 1.8
27+
}
2628
}
2729

2830
dependencies {
2931
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
30-
api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8'
31-
api 'androidx.appcompat:appcompat:1.1.0'
32-
api 'androidx.core:core-ktx:1.3.1'
32+
api 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.4.1'
33+
api 'androidx.appcompat:appcompat:1.2.0'
34+
api 'androidx.core:core-ktx:1.3.2'
3335

34-
api 'com.squareup.retrofit2:retrofit:2.6.2'
35-
api 'com.squareup.retrofit2:converter-gson:2.6.1'
36+
api 'com.squareup.retrofit2:retrofit:2.7.2'
37+
api 'com.squareup.retrofit2:converter-gson:2.7.2'
3638
//noinspection GradleDependency
3739
api "com.squareup.okhttp3:okhttp:3.12.6"
3840
//noinspection GradleDependency
3941
api "com.squareup.okio:okio:2.3.0"
4042
api 'com.github.ssseasonnn:ClarityPotion:1.0.2'
4143

4244
testImplementation 'junit:junit:4.12'
43-
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
44-
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
45+
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
46+
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
4547
}

downloadx/src/main/java/zlc/season/downloadx/DownloadX.kt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,5 @@ fun String.download(coroutineScope: CoroutineScope? = null): DownloadTask {
1111
val downloadParams = DownloadParams(this)
1212
val downloadConfig = DownloadConfig(coroutineScope)
1313
val downloadTask = DownloadTask(downloadParams, downloadConfig)
14-
downloadTask.start()
1514
return downloadTask
1615
}

downloadx/src/main/java/zlc/season/downloadx/downloader/DownloadTask.kt

Lines changed: 26 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
package zlc.season.downloadx.downloader
22

33
import kotlinx.coroutines.*
4-
import kotlinx.coroutines.flow.Flow
5-
import kotlinx.coroutines.flow.MutableStateFlow
6-
import kotlinx.coroutines.flow.flatMapConcat
7-
import kotlinx.coroutines.flow.flow
4+
import kotlinx.coroutines.flow.*
85
import zlc.season.downloadx.Progress
96
import zlc.season.downloadx.core.Default
107
import zlc.season.downloadx.core.request
@@ -14,7 +11,6 @@ import zlc.season.downloadx.utils.fileName
1411
import zlc.season.downloadx.utils.isSupportRange
1512
import zlc.season.downloadx.utils.log
1613

17-
@ExperimentalCoroutinesApi
1814
open class DownloadTask(
1915
private val downloadParams: DownloadParams,
2016
private val downloadConfig: DownloadConfig
@@ -24,9 +20,12 @@ open class DownloadTask(
2420

2521
private val coroutineScope = downloadConfig.coroutineScope ?: GlobalScope
2622

27-
private val progressStateFlow = MutableStateFlow(0)
23+
private val downloadStateFlow = MutableStateFlow(0)
2824

2925
fun start() {
26+
if (downloadJob != null) {
27+
downloadJob?.cancel()
28+
}
3029
downloadJob = coroutineScope.launch {
3130
val response = request(downloadParams.url, downloadConfig.header)
3231
if (!response.isSuccessful) {
@@ -42,44 +41,47 @@ open class DownloadTask(
4241
}
4342

4443
downloader = if (response.isSupportRange()) {
45-
RangeDownloader(coroutineScope)
44+
NormalDownloader(coroutineScope)
4645
} else {
4746
NormalDownloader(coroutineScope)
4847
}
49-
downloader?.download(downloadParams, downloadConfig, response)
50-
51-
stateTrigger()
48+
val downloadJob = async {
49+
downloader?.download(downloadParams, downloadConfig, response)
50+
}
51+
val stateTriggerJob = async { stateTrigger() }
52+
downloadJob.join()
53+
stateTriggerJob.join()
5254
}
53-
downloadJob?.start()
5455
}
5556

5657
fun stop() {
5758
downloadJob?.cancel()
5859
}
5960

61+
@FlowPreview
6062
fun progress(interval: Long = 100): Flow<Progress> {
61-
// return progressStateFlow.flatMapConcat {
62-
return flow {
63-
var progress = progress()
64-
// if (progress.isComplete()) {
65-
// emit(progress)
66-
// } else {
67-
while (downloadJob?.isActive == true && !progress.isComplete()) {
68-
delay(interval)
69-
progress = progress()
70-
emit(progress)
63+
return downloadStateFlow.flatMapConcat {
64+
flow {
65+
var progress = progress()
66+
if (progress.isComplete()) {
67+
emit(progress)
68+
} else {
69+
while (downloadJob?.isActive == true && !progress.isComplete()) {
70+
delay(interval)
71+
progress = progress()
72+
emit(progress)
73+
}
74+
}
7175
}
7276
}
73-
// }
74-
// }
7577
}
7678

7779
suspend fun progress(): Progress {
7880
return downloader?.queryProgress() ?: Progress()
7981
}
8082

8183
private fun stateTrigger() {
82-
progressStateFlow.value = progressStateFlow.value + 1
84+
downloadStateFlow.value = downloadStateFlow.value + 1
8385
}
8486

8587
private fun Progress.isComplete(): Boolean {

downloadx/src/main/java/zlc/season/downloadx/downloader/Downloader.kt

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,16 +27,21 @@ interface Downloader {
2727
)
2828
}
2929

30-
@ObsoleteCoroutinesApi
3130
abstract class BaseDownloader(protected val coroutineScope: CoroutineScope) : Downloader {
32-
protected var totalSize: Long = 0
33-
protected var downloadSize: Long = 0
31+
protected var totalSize: Long = 0L
32+
protected var downloadSize: Long = 0L
3433
protected var isChunked: Boolean = false
3534

35+
private val progress = Progress()
36+
3637
override var actor = coroutineScope.actor<Action> {
3738
for (action in channel) {
3839
if (action is Action.QueryProgress) {
39-
action.progress.complete(Progress(downloadSize, totalSize, isChunked))
40+
action.progress.complete(progress.also {
41+
it.downloadSize = downloadSize
42+
it.totalSize = totalSize
43+
it.isChunked = isChunked
44+
})
4045
}
4146
}
4247
}

downloadx/src/main/java/zlc/season/downloadx/downloader/NormalDownloader.kt

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -25,29 +25,29 @@ class NormalDownloader(coroutineScope: CoroutineScope) : BaseDownloader(coroutin
2525
response: Response<ResponseBody>
2626
) {
2727
val body = response.body()
28-
if (body == null) {
29-
"Url [${downloadParams.url}] response body is NULL!".log()
30-
return
31-
}
32-
33-
file = downloadParams.file()
34-
shadowFile = file.shadow()
28+
body.use {
29+
if (body == null) {
30+
"Url [${downloadParams.url}] response body is NULL!".log()
31+
return
32+
}
33+
file = downloadParams.file()
34+
shadowFile = file.shadow()
3535

36-
val contentLength = response.contentLength()
37-
val isChunked = response.isChunked()
36+
val contentLength = response.contentLength()
37+
val isChunked = response.isChunked()
3838

39-
downloadPrepare(downloadParams, contentLength)
39+
downloadPrepare(downloadParams, contentLength)
4040

41-
if (alreadyDownloaded) {
42-
this.downloadSize = contentLength
43-
this.totalSize = contentLength
44-
this.isChunked = isChunked
45-
} else {
46-
this.totalSize = contentLength
47-
this.downloadSize = 0
48-
this.isChunked = isChunked
49-
50-
startDownload(body)
41+
if (alreadyDownloaded) {
42+
this.downloadSize = contentLength
43+
this.totalSize = contentLength
44+
this.isChunked = isChunked
45+
} else {
46+
this.totalSize = contentLength
47+
this.downloadSize = 0
48+
this.isChunked = isChunked
49+
startDownload(body)
50+
}
5151
}
5252
}
5353

downloadx/src/main/java/zlc/season/downloadx/downloader/RangeDownloader.kt

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ class RangeDownloader(coroutineScope: CoroutineScope) : BaseDownloader(coroutine
3636
downloadSize = response.contentLength()
3737
totalSize = response.contentLength()
3838
} else {
39-
totalSize = response.contentLength()
39+
val last = rangeTmpFile.lastProgress()
40+
downloadSize = last.downloadSize
41+
totalSize = last.totalSize
4042
startDownload(downloadParams, downloadConfig, response)
4143
}
4244
}
@@ -93,10 +95,6 @@ class RangeDownloader(coroutineScope: CoroutineScope) : BaseDownloader(coroutine
9395
downloadConfig: DownloadConfig,
9496
response: Response<ResponseBody>
9597
) {
96-
val last = rangeTmpFile.lastProgress()
97-
downloadSize = last.downloadSize
98-
totalSize = last.totalSize
99-
10098
val progressChannel = coroutineScope.actor<RangeMsg> {
10199
for (msg in channel) {
102100
downloadSize += msg.readLen

0 commit comments

Comments
 (0)