我正在尝试从具有翻新和rxjava的api下载文件列表,我读了很多书,但是我无法弄清楚翻新和rxjava如何协同工作,而且我不确定观察者必须使用哪种线程
我正在尝试更改应用程序的文件下载过程,该过程最初是使用doAsync(Anko)进行的,该应用程序在具有api 19和互联网连接速度缓慢的非常有限的平板电脑中运行。最初的问题是,平板电脑在第一个文件下载中会出现内存泄漏(大约200个文件,使用100 mb的内存(全部))。因此,经过长时间的研究,我决定尝试使用Rx和翻新程序重写下载过程的代码(但我在Kotlin或Movil方面没有太多经验)。
我的模特
data class File(
val id: String
) //staging
data class Movimientos(val borrar: List<File>,
val descargar: List<File>,
val estructura: List<Nodo>)
data class Nodo( val id: String,
val root: String,
val name: String,
val file: Boolean,
val descargado: Boolean,
val version: Int)
我的服务
//return a json with a list of files to download (and to more list -not important for now-)
@GET("index.php")
fun getMovimientos(@Query("r") r: String = "movimientos",
@Query("imei") id: String,
@Query("access-token") accesstoken: String): Observable<Movimientos>
@Streaming
@GET("index.php")
fun getArchivo(@Query("r") r: String = "descarga",
@Query("id") fileID: String,
@Query("access-token") accesstoken: String): Observable<ResponseBody>
companion object {
fun create(): WikiApiService {
val retrofit = Retrofit.Builder()
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.baseUrl("https://url/api.biblioteca/")
.build()
return retrofit.create(WikiApiService::class.java)
}
}
要求获取要下载的列表并调用下载过程
private fun beginSearch(searchString: String) {
disposable = wikiApiServe.getMovimientos("movimientos", "d55a374eebc242a5", "XXXXXXXXXXXX")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(
{
result -> txt_search_result.text = "${result.estructura.size} tamaño estructura"
Log.d("Estructura: ", "Es: ${result.estructura}")
//var aux =10
result.estructura.forEach {
nodo ->
if (nodo.file/) {
//aux--
descargarArchivo(nodo.id)
}
}
},
{ error -> Toast.makeText(this, error.message, Toast.LENGTH_SHORT).show() }
)
}
要求下载功能
private fun descargarArchivo(id: String){
disposable = wikiApiServe.getArchivo("descarga", id, "XXXXXXXXXXX")
.subscribeOn(Schedulers.io())
.observeOn(Schedulers.newThread())
.subscribe(
{
//result -> txt_search_result.text = "${result.estructura.size} tamaño estructura"
totalDescargas = totalDescargas +1
Log.d("Descargado: ", "Id archivo: $id bytes: ${it.bytes().size} Total descargas: $totalDescargas")
//total.text = totalDescargas
},
{ error -> Toast.makeText(this, error.message, Toast.LENGTH_SHORT).show() }
)
}
当我运行代码时,该应用程序会下载一些文件(大约五个),然后不再执行其他操作(logcat向我发送了很多GC_FOR_ALLOC警告和跳帧信息)。我尝试限制对下载方法的调用(以编程方式将计数变量(限制为10),以避免尝试尝试下载200个文件),但仍然可以发送GC_FOR_ALLOC,并且我必须添加一些代码来下载其他190个文件每十个批次(但是我认为这不是最好的方法)。即时消息,我不得不使用观察者列表,并使用flatMap调用downlad函数,这是另一个麻烦。但是我不知道如何使用这种方法。
我尝试使用另一个线程(每次下载一个新线程),但是线程池有错误
答案 0 :(得分:1)
我将转换代码以使用Observable.fromIterable和flatMap,flatMap的重载带有maxConcurrency参数,可用来避免创建Schedulers.io()默认将执行的线程数量不受限制。 / p>
在包含foreach循环的订阅之前,添加对flatMap的调用,如下所示。然后,每次调用getArchivo的结果都会调用您的订阅,因此将其内容替换为您当前在getArchivo订阅中拥有的代码
private fun beginSearch(searchString: String) {
disposable = wikiApiServe.getMovimientos("movimientos", "d55a374eebc242a5", "XXXXXXXXXXXX")
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.flatMap { result ->
Observable.fromIterable(result.estructura)
.flatMap({ nodo ->
wikiApiServe.getArchivo("descarga", nodo.id, "XXXXXXXXXXX")
.subscribeOn(Schedulers.io())
}, 4)
}
.subscribe(
{
totalDescargas = totalDescargas +1
Log.d("Descargado: ", "Id archivo: $id bytes: ${it.bytes().size} Total descargas: $totalDescargas")
},
{ error -> Toast.makeText(this, error.message, Toast.LENGTH_SHORT).show() }