Merge pull request #1781 from ag2s20150909/master

Cronet共用okhttp的线程池
pull/1785/head
kunfei 3 years ago committed by GitHub
commit 31fd74a3f2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 44
      app/src/main/java/io/legado/app/help/http/cronet/AbsCallBack.kt
  2. 14
      app/src/main/java/io/legado/app/help/http/cronet/CronetHelper.kt
  3. 1
      app/src/main/java/io/legado/app/help/http/cronet/CronetInterceptor.kt
  4. 8
      app/src/main/java/io/legado/app/help/http/cronet/CronetLoader.kt
  5. 53
      app/src/main/java/io/legado/app/help/http/cronet/NewCallBack.kt
  6. 39
      app/src/main/java/io/legado/app/help/http/cronet/OldCallback.kt
  7. 4
      app/src/main/java/io/legado/app/utils/ThrowableExtensions.kt

@ -2,7 +2,7 @@ package io.legado.app.help.http.cronet
import io.legado.app.help.http.okHttpClient import io.legado.app.help.http.okHttpClient
import io.legado.app.utils.DebugLog import io.legado.app.utils.DebugLog
import io.legado.app.utils.rethrowAsIOException import io.legado.app.utils.asIOException
import okhttp3.* import okhttp3.*
import okhttp3.EventListener import okhttp3.EventListener
import okhttp3.MediaType.Companion.toMediaTypeOrNull import okhttp3.MediaType.Companion.toMediaTypeOrNull
@ -27,12 +27,24 @@ abstract class AbsCallBack(
var mResponse: Response var mResponse: Response
var mException: IOException? = null
private var followCount = 0 private var followCount = 0
@Throws(IOException::class)
abstract fun waitForDone(urlRequest: UrlRequest): Response abstract fun waitForDone(urlRequest: UrlRequest): Response
/**
* 当发生错误时通知子类终止阻塞抛出错误
* @param error
*/
abstract fun onError(error: IOException)
/**
* 请求成功后通知子类结束阻塞返回response
* @param response
*/
abstract fun onSuccess(response: Response)
override fun onRedirectReceived( override fun onRedirectReceived(
request: UrlRequest, request: UrlRequest,
@ -41,10 +53,13 @@ abstract class AbsCallBack(
) { ) {
if (followCount > MAX_FOLLOW_COUNT) { if (followCount > MAX_FOLLOW_COUNT) {
request.cancel() request.cancel()
mException = IOException("Too many redirect") onError(IOException("Too many redirect"))
return
} }
if (mCall.isCanceled()) { if (mCall.isCanceled()) {
mException = IOException("Request Canceled") onError(IOException("Request Canceled"))
request.cancel()
return
} }
followCount += 1 followCount += 1
val client = okHttpClient val client = okHttpClient
@ -55,7 +70,7 @@ abstract class AbsCallBack(
} else if (okHttpClient.followRedirects) { } else if (okHttpClient.followRedirects) {
request.followRedirect() request.followRedirect()
} else { } else {
mException = IOException("Too many redirect") onError(IOException("Too many redirect"))
request.cancel() request.cancel()
} }
} }
@ -73,7 +88,7 @@ abstract class AbsCallBack(
} }
@Throws(Exception::class) @Throws(IOException::class)
override fun onReadCompleted( override fun onReadCompleted(
request: UrlRequest, request: UrlRequest,
info: UrlResponseInfo, info: UrlResponseInfo,
@ -83,7 +98,7 @@ abstract class AbsCallBack(
if (mCall.isCanceled()) { if (mCall.isCanceled()) {
request.cancel() request.cancel()
mException = IOException("Request Canceled") onError(IOException("Request Canceled"))
} }
byteBuffer.flip() byteBuffer.flip()
@ -91,9 +106,9 @@ abstract class AbsCallBack(
try { try {
buffer.write(byteBuffer) buffer.write(byteBuffer)
} catch (e: IOException) { } catch (e: IOException) {
DebugLog.i(javaClass.name, "IOException during ByteBuffer read. Details: ", e) DebugLog.e(javaClass.name, "IOException during ByteBuffer read. Details: ", e)
mException = IOException("IOException during ByteBuffer read. Details:", e) onError(IOException("IOException during ByteBuffer read. Details:", e))
throw e return
} }
byteBuffer.clear() byteBuffer.clear()
request.read(byteBuffer) request.read(byteBuffer)
@ -108,7 +123,8 @@ abstract class AbsCallBack(
buffer.asResponseBody(contentType) buffer.asResponseBody(contentType)
val newRequest = originalRequest.newBuilder().url(info.url).build() val newRequest = originalRequest.newBuilder().url(info.url).build()
this.mResponse = this.mResponse.newBuilder().body(responseBody).request(newRequest).build() this.mResponse = this.mResponse.newBuilder().body(responseBody).request(newRequest).build()
DebugLog.i(javaClass.simpleName, "end[${info.negotiatedProtocol}]${info.url}") onSuccess(this.mResponse)
//DebugLog.i(javaClass.simpleName, "end[${info.negotiatedProtocol}]${info.url}")
eventListener?.callEnd(mCall) eventListener?.callEnd(mCall)
if (responseCallback != null) { if (responseCallback != null) {
@ -123,8 +139,8 @@ abstract class AbsCallBack(
//UrlResponseInfo可能为null //UrlResponseInfo可能为null
override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) { override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) {
DebugLog.i(javaClass.name, error.message.toString()) DebugLog.e(javaClass.name, error.message.toString())
mException = error.rethrowAsIOException() onError(error.asIOException())
this.eventListener?.callFailed(mCall, error) this.eventListener?.callFailed(mCall, error)
responseCallback?.onFailure(mCall, error) responseCallback?.onFailure(mCall, error)
} }
@ -132,7 +148,7 @@ abstract class AbsCallBack(
override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) { override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) {
super.onCanceled(request, info) super.onCanceled(request, info)
this.eventListener?.callEnd(mCall) this.eventListener?.callEnd(mCall)
mException = IOException("Cronet Request Canceled") onError(IOException("Cronet Request Canceled"))
} }

@ -2,6 +2,7 @@ package io.legado.app.help.http.cronet
import io.legado.app.constant.AppLog import io.legado.app.constant.AppLog
import io.legado.app.help.config.AppConfig import io.legado.app.help.config.AppConfig
import io.legado.app.help.http.okHttpClient
import io.legado.app.utils.DebugLog import io.legado.app.utils.DebugLog
import okhttp3.Headers import okhttp3.Headers
import okhttp3.MediaType import okhttp3.MediaType
@ -13,11 +14,8 @@ import org.chromium.net.UploadDataProviders
import org.chromium.net.UrlRequest import org.chromium.net.UrlRequest
import splitties.init.appCtx import splitties.init.appCtx
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
//val executor: ExecutorService by lazy { Executors.newCachedThreadPool() }
val executor: ExecutorService by lazy { Executors.newCachedThreadPool() }
val cronetEngine: ExperimentalCronetEngine? by lazy { val cronetEngine: ExperimentalCronetEngine? by lazy {
if (!AppConfig.isGooglePlay) { if (!AppConfig.isGooglePlay) {
@ -48,7 +46,11 @@ fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest? {
val url = request.url.toString() val url = request.url.toString()
val headers: Headers = request.headers val headers: Headers = request.headers
val requestBody = request.body val requestBody = request.body
return cronetEngine?.newUrlRequestBuilder(url, callback, executor)?.apply { return cronetEngine?.newUrlRequestBuilder(
url,
callback,
okHttpClient.dispatcher.executorService
)?.apply {
setHttpMethod(request.method)//设置 setHttpMethod(request.method)//设置
allowDirectExecutor() allowDirectExecutor()
headers.forEachIndexed { index, _ -> headers.forEachIndexed { index, _ ->
@ -65,7 +67,7 @@ fun buildRequest(request: Request, callback: UrlRequest.Callback): UrlRequest? {
requestBody.writeTo(buffer) requestBody.writeTo(buffer)
setUploadDataProvider( setUploadDataProvider(
UploadDataProviders.create(buffer.readByteArray()), UploadDataProviders.create(buffer.readByteArray()),
executor okHttpClient.dispatcher.executorService
) )
} }

@ -49,7 +49,6 @@ class CronetInterceptor(private val cookieJar: CookieJar?) : Interceptor {
OldCallback(request, call) OldCallback(request, call)
} }
buildRequest(request, callBack)?.let { buildRequest(request, callBack)?.let {
it.start()
return callBack.waitForDone(it) return callBack.waitForDone(it)
} }
return null return null

@ -268,7 +268,8 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
return return
} }
download = true download = true
executor.execute {
Coroutine.async {
val result = downloadFileIfNotExist(url, downloadTempFile) val result = downloadFileIfNotExist(url, downloadTempFile)
DebugLog.d(javaClass.simpleName, "download result:$result") DebugLog.d(javaClass.simpleName, "download result:$result")
//文件md5再次校验 //文件md5再次校验
@ -279,7 +280,7 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
downloadTempFile.deleteOnExit() downloadTempFile.deleteOnExit()
} }
download = false download = false
return@execute return@async
} }
DebugLog.d(javaClass.simpleName, "download success, copy to $destSuccessFile") DebugLog.d(javaClass.simpleName, "download success, copy to $destSuccessFile")
//下载成功拷贝文件 //下载成功拷贝文件
@ -289,6 +290,9 @@ object CronetLoader : CronetEngine.Builder.LibraryLoader() {
@Suppress("SameParameterValue") @Suppress("SameParameterValue")
deleteHistoryFile(parentFile!!, null) deleteHistoryFile(parentFile!!, null)
} }
// executor.execute {
//
// }
} }
/** /**

@ -6,11 +6,8 @@ import androidx.annotation.RequiresApi
import okhttp3.Call import okhttp3.Call
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.chromium.net.CronetException
import org.chromium.net.UrlRequest import org.chromium.net.UrlRequest
import org.chromium.net.UrlResponseInfo
import java.io.IOException import java.io.IOException
import java.nio.ByteBuffer
import java.util.concurrent.CompletableFuture import java.util.concurrent.CompletableFuture
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -21,45 +18,29 @@ class NewCallBack(originalRequest: Request, mCall: Call) : AbsCallBack(originalR
@Throws(IOException::class) @Throws(IOException::class)
override fun waitForDone(urlRequest: UrlRequest): Response { override fun waitForDone(urlRequest: UrlRequest): Response {
return responseFuture.get(mCall.timeout().timeoutNanos(), TimeUnit.NANOSECONDS) urlRequest.start()
return if (mCall.timeout().timeoutNanos() > 0) {
responseFuture.get(mCall.timeout().timeoutNanos(), TimeUnit.NANOSECONDS)
} else {
return responseFuture.get()
} }
override fun onRedirectReceived(
request: UrlRequest,
info: UrlResponseInfo,
newLocationUrl: String
) {
super.onRedirectReceived(request, info, newLocationUrl)
if (mException != null) {
responseFuture.completeExceptionally(mException)
}
}
override fun onReadCompleted(
request: UrlRequest,
info: UrlResponseInfo,
byteBuffer: ByteBuffer
) {
super.onReadCompleted(request, info, byteBuffer)
if (mException != null) {
responseFuture.completeExceptionally(mException)
}
}
override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) {
super.onSucceeded(request, info)
responseFuture.complete(mResponse)
} }
override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) { /**
super.onFailed(request, info, error) * 当发生错误时通知子类终止阻塞抛出错误
responseFuture.completeExceptionally(mException) * @param error
*/
override fun onError(error: IOException) {
responseFuture.completeExceptionally(error)
} }
override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) { /**
super.onCanceled(request, info) * 请求成功后通知子类结束阻塞返回response
responseFuture.completeExceptionally(mException) * @param response
*/
override fun onSuccess(response: Response) {
responseFuture.complete(response)
} }

@ -4,20 +4,19 @@ import android.os.ConditionVariable
import okhttp3.Call import okhttp3.Call
import okhttp3.Request import okhttp3.Request
import okhttp3.Response import okhttp3.Response
import org.chromium.net.CronetException
import org.chromium.net.UrlRequest import org.chromium.net.UrlRequest
import org.chromium.net.UrlResponseInfo
import java.io.IOException import java.io.IOException
import java.nio.ByteBuffer
class OldCallback(originalRequest: Request, mCall: Call) : AbsCallBack(originalRequest, mCall) { class OldCallback(originalRequest: Request, mCall: Call) : AbsCallBack(originalRequest, mCall) {
private val mResponseCondition = ConditionVariable() private val mResponseCondition = ConditionVariable()
private var mException: IOException? = null
@Throws(IOException::class) @Throws(IOException::class)
override fun waitForDone(urlRequest: UrlRequest): Response { override fun waitForDone(urlRequest: UrlRequest): Response {
//获取okhttp call的完整请求的超时时间 //获取okhttp call的完整请求的超时时间
val timeOutMs: Long = mCall.timeout().timeoutNanos() / 1000000 val timeOutMs: Long = mCall.timeout().timeoutNanos() / 1000000
urlRequest.start()
if (timeOutMs > 0) { if (timeOutMs > 0) {
mResponseCondition.block(timeOutMs) mResponseCondition.block(timeOutMs)
} else { } else {
@ -32,35 +31,25 @@ class OldCallback(originalRequest: Request, mCall: Call) : AbsCallBack(originalR
if (mException != null) { if (mException != null) {
throw mException as IOException throw mException as IOException
} }
return this.mResponse return mResponse
} }
/**
override fun onReadCompleted( * 当发生错误时通知子类终止阻塞抛出错误
request: UrlRequest, * @param error
info: UrlResponseInfo, */
byteBuffer: ByteBuffer override fun onError(error: IOException) {
) { mException = error
super.onReadCompleted(request, info, byteBuffer)
if (mException != null) {
mResponseCondition.open() mResponseCondition.open()
} }
}
override fun onSucceeded(request: UrlRequest, info: UrlResponseInfo) { /**
super.onSucceeded(request, info) * 请求成功后通知子类结束阻塞返回response
* @param response
*/
override fun onSuccess(response: Response) {
mResponseCondition.open() mResponseCondition.open()
} }
override fun onFailed(request: UrlRequest, info: UrlResponseInfo?, error: CronetException) {
super.onFailed(request, info, error)
mResponseCondition.open()
}
override fun onCanceled(request: UrlRequest?, info: UrlResponseInfo?) {
super.onCanceled(request, info)
mResponseCondition.open()
}
} }

@ -12,8 +12,8 @@ val Throwable.msg: String
} }
} }
fun Throwable.rethrowAsIOException(): IOException { fun Throwable.asIOException(): IOException {
val newException = IOException(this.message) val newException = IOException(this.message)
newException.initCause(this) newException.initCause(this)
throw newException return newException
} }
Loading…
Cancel
Save