Rxhttp - lightweight, extensible, easy to use, perfectly compatible with MVVM, MVC architecture network encapsulation class library

Antarctic glacier snow 2021-02-23 13:04:37
rxhttp lightweight extensible easy use


Preface

RxHttp Is based on RxJava2+Retrofit 2.9.0+OkHttp 4.9.0 Lightweight implementation , Perfect compatibility MVVM Architecture of network request encapsulation class library , Cabinet and delicate , Simple and easy to use , Easy to handle network requests .

GitHub

https://github.com/kongpf8848/RxHttp

Bright spot

  • Very little code , Insufficient class library size 100kb, But it's good enough for most of APP Network request task for , Concentrated is the essence _^_

  • Perfect compatibility MVVM,MVC framework , compatible Kotlin and Java,Kotlin+MVVM+RxHttp The combination is more sour and refreshing ,MVVM The official recommendation , Hold tight Google The thighs are right

  • Perfect solution to the thorny problem of generic type erasure , Restore the real type of a generic

  • Born to support web requests and Activity,Fragment Life cycle binding , When the interface is destroyed, the network request callback will be cancelled automatically

  • Natural support BaseUrl, Supports dynamic incoming Url

  • Support customization OkHttpClient.Builder, Highly customizable network request parameters

  • Support Glide Share one with network request OkHttpClient, make the best of OkHttpClient Thread pool and connection pool of , Most of the time, one App One OkHttpClient That's enough

  • Support GET,POST,PUT,DELETE Etc , Support file upload and progress monitoring , Support to upload multiple files at the same time , Support Uri Upload

  • Support file download and progress monitoring , Support large file download , Support breakpoint download

Use requirement

Project based on AndroidX,Java8+,minSdkVersion>=21

Use

implementation 'com.github.kongpf8848:RxHttp:1.0.11'

To configure ( Optional )

 RxHttpConfig.getInstance()
/**
* Failed retries
*/
.maxRetries(3)
/**
* Time interval between failed retries
*/
.retryDelayMillis(200)
/**
* Customize OkHttpClient.Builder(),RxHttp Support customization OkHttpClient.Builder(),
* If not defined , Then use RxHttp default OkHttpClient.Builder()
*/
.builder(OkHttpClient.Builder().apply {
connectTimeout(60, TimeUnit.SECONDS)
readTimeout(60, TimeUnit.SECONDS)
writeTimeout(60, TimeUnit.SECONDS)
/**
* DEBUG In mode , Add log interceptor , It is recommended to use RxHttp Medium FixHttpLoggingInterceptor, Use OkHttp Of HttpLoggingInterceptor When uploading and downloading, there will be IOException problem
*/
if (BuildConfig.DEBUG) {
addInterceptor(FixHttpLoggingInterceptor().apply {
level = FixHttpLoggingInterceptor.Level.BODY
})
}
})

Based on using

  • GET/POST/PUT/DELETE/ Upload request
 RxHttp.getInstance()
/**
* get: Request type , for get,post,put,delete,upload, They correspond to each other GET/POST/PUT/DELETE/ Upload request
* context: Context , for Context,Activity or Fragment type , When context by Activity or Fragment Network request and lifecycle binding
*/
.get(context)
/**
* request url, Such as https://www.baidu.com
*/
.url("xxx")
/**
* Request parameter key value pairs , The type is Map<String, Any?>?, Such as hashMapOf("name" to "jack")
*/
.params(map)
/**
* Each network request corresponds to tag value , for null, Used for subsequent manual operation according to tag Cancel the specified network request
*/
.tag("xxx")
/**
* HttpCallback: Network callback , Parameters xxx To return the data model corresponding to the data ,
* similar RxJava Medium Observer,onComplete Only in onNext Execute after callback , If there is an error, it will only call back onError But not onComplete
*/
.enqueue(object : HttpCallback<xxx>() {
/**
* http Callback at the beginning of the request
*/
override fun onStart() {
}
/**
* http Callback on successful request
*/
override fun onNext(response: xxx?) {
}
/**
* http Callback on request failure
*/
override fun onError(e: Throwable?) {
}
/**
* http Call back when the request completes successfully
*/
override fun onComplete() {
}
/**
* Upload progress callback , The request type is upload It will be called back when it's done
*/
override fun onProgress(readBytes: Long, totalBytes: Long) {
}
})
  • Download request
 RxHttp.getInstance()
/**
* download: Request type , Download request
* context: Context , If you don't need to bind to the lifecycle , It should be delivered applicationContext
*/
.download(context)
/**
* Save the path
*/
.dir(dir)
/**
* Save the file name
*/
.filename(filename)
/**
* Whether it is a breakpoint download , The default is false
*/
.breakpoint(true)
/**
* Download address , Such as http://study.163.com/pub/ucmooc/ucmooc-android-official.apk
*/
.url(url)
/**
* request Tag
*/
.tag(null)
/**
* Download callback
*/
.enqueue(object: DownloadCallback() {
/**
* Callback at the start of download
*/
override fun onStart() {
}
/**
* Call back when the download is complete
*/
override fun onNext(response: DownloadInfo?) {
}
/**
* Call back when download fails
*/
override fun onError(e: Throwable?) {
}
/**
* When the download is complete, call back
*/
override fun onComplete() {
}
/**
* Download progress callback
*/
override fun onProgress(readBytes: Long, totalBytes: Long) {
}
})
  • Cancel the request
 /**
* tag:Any?, request Tag, Corresponding to... In the network request Tag value
* If not null, Cancel the specified network request ,
* If null, Cancel all network requests
*/
RxHttp.getInstance().cancelRequest(tag)

Project practice

Here we assume that the data format returned by the server is {"code":xxx,"data":T,"msg":""}, among code Is the response code , integer , be equal to 200 When it comes to success , The rest are failures ,data The corresponding data type is generic (boolean,int,double,String, object { }, Array [ ] Other types )

{
"code": 200,
"data":T,
"msg": ""
}

Corresponding Response Class is

class TKResponse<T>(val code:Int,val msg: String?, val data: T?) : Serializable {
companion object{
const val STATUS_OK=200
}
fun isSuccess():Boolean{
return code== STATUS_OK
}
}
  • MVC project

    • Definition MVCHttpCallback, It is used to call back the result of network request to UI Interface
    abstract class MVCHttpCallback<T> {
    private val type: Type
    init {
    val arg = TypeUtil.getType(javaClass)
    type = TypeBuilder
    .newInstance(TKResponse::class.java)
    .addTypeParam(arg)
    .build()
    }
    fun getType(): Type {
    return this.type
    }
    /**
    * Callback at the beginning of the request , You can load here loading Dialog, etc , Null implementation by default
    */
    open fun onStart() {}
    /**
    * Abstract method , Request successful callback , The returned content is generic , Corresponding TKResponse Of data
    */
    abstract fun onSuccess(result: T?)
    /**
    * Abstract method , Request failed callback , The returned content is code( Error code ),msg( error message )
    */
    abstract fun onFailure(code: Int, msg: String?)
    /**
    * Upload progress callback , Null implementation by default
    */
    open fun onProgress(readBytes: Long, totalBytes: Long) {}
    /**
    * Callback on request completion , This method will not be called back until the request is successful , Null implementation by default
    */
    open fun onComplete() {}
    }
    
    • Define the network interface , encapsulation GET/POST Wait for network request
    object MVCApi {
    /**
    * GET request
    * context: Context
    * url: request url
    * params: parameter list , for null
    * tag: Identify a network request
    * callback: Network request callback
    */
    inline fun <reified T> httpGet(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null,
    callback: MVCHttpCallback<T>
    ) {
    RxHttp.getInstance().get(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(simpleHttpCallback(callback))
    }
    /**
    * POST request
    * context: Context
    * url: request url
    * params: parameter list , for null
    * tag: Identify a network request
    * callback: Network request callback
    */
    inline fun <reified T> httpPost(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null,
    callback: MVCHttpCallback<T>
    ) {
    RxHttp.getInstance().post(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(simpleHttpCallback(callback))
    }
    ......
    inline fun <reified T> simpleHttpCallback(callback: MVCHttpCallback<T>): HttpCallback<TKResponse<T>> {
    return object : HttpCallback<TKResponse<T>>(callback.getType()) {
    override fun onStart() {
    super.onStart()
    callback.onStart()
    }
    override fun onNext(response: TKResponse<T>?) {
    if (response != null) {
    if (response.isSuccess()) {
    callback.onSuccess(response.data)
    } else {
    return onError(ServerException(response.code, response.msg))
    }
    } else {
    return onError(NullResponseException(TKErrorCode.ERRCODE_RESPONSE_NULL, TKErrorCode.ERRCODE_RESPONSE_NULL_DESC))
    }
    }
    override fun onError(e: Throwable?) {
    handleThrowable(e).run {
    callback.onFailure(first, second)
    }
    }
    override fun onComplete() {
    super.onComplete()
    callback.onComplete()
    }
    override fun onProgress(readBytes: Long, totalBytes: Long) {
    super.onProgress(readBytes, totalBytes)
    callback.onProgress(readBytes, totalBytes)
    }
    }
    }
    
    • stay View Layering as Activity Call the network interface
    MVCApi.httpGet(
    context = baseActivity,
    url = TKURL.URL_GET,
    params = null,
    tag = null,
    callback = object : MVCHttpCallback<List<Banner>>() {
    override fun onStart() {
    LogUtils.d(TAG, "onButtonGet onStart() called")
    }
    override fun onSuccess(result: List<Banner>?) {
    Log.d(TAG, "onButtonGet onSuccess() called with: result = $result")
    }
    override fun onFailure(code: Int, msg: String?) {
    Log.d(TAG, "onButtonGet onFailure() called with: code = $code, msg = $msg")
    }
    override fun onComplete() {
    Log.d(TAG, "onButtonGet onComplete() called")
    }
    })
    

    For specific use, please refer to demo Code ,demo There are detailed examples in MVC How to use the project RxHttp

  • MVVM project

    • Definition Activity Base class BaseMvvmActivity
    abstract class BaseMvvmActivity<VM : BaseViewModel, VDB : ViewDataBinding> : AppCompatActivity(){
    lateinit var viewModel: VM
    lateinit var binding: VDB
    protected abstract fun getLayoutId(): Int
    final override fun onCreate(savedInstanceState: Bundle?) {
    onCreateStart(savedInstanceState)
    super.onCreate(savedInstanceState)
    binding = DataBindingUtil.setContentView(this, getLayoutId())
    binding.lifecycleOwner = this
    createViewModel()
    onCreateEnd(savedInstanceState)
    }
    protected open fun onCreateStart(savedInstanceState: Bundle?) {}
    protected open fun onCreateEnd(savedInstanceState: Bundle?) {}
    /**
    * establish ViewModel
    */
    private fun createViewModel() {
    val type = findType(javaClass.genericSuperclass)
    val modelClass = if (type is ParameterizedType) {
    type.actualTypeArguments[0] as Class<VM>
    } else {
    BaseViewModel::class.java as Class<VM>
    }
    viewModel = ViewModelProvider(this).get(modelClass)
    }
    private fun findType(type: Type): Type?{
    return when(type){
    is ParameterizedType -> type
    is Class<*> ->{
    findType(type.genericSuperclass)
    }
    else ->{
    null
    }
    }
    }
    }
    
    • Definition ViewModel Base class of BaseViewModel
    open class BaseViewModel(application: Application) : AndroidViewModel(application) {
    /**
    * Network warehouse
    */
    protected val networkbaseRepository: NetworkRepository = NetworkRepository.instance
    /**
    * Context
    */
    protected var context: Context = application.applicationContext
    }
    
    • Define the network warehouse , Encapsulating network interfaces
    /**
    * MVVM Architecture network warehouse
    * UI->ViewModel->Repository->LiveData(ViewModel)->UI
    */
    class NetworkRepository private constructor() {
    companion object {
    val instance = NetworkRepository.holder
    }
    private object NetworkRepository {
    val holder = NetworkRepository()
    }
    inline fun <reified T> wrapHttpCallback(): MvvmHttpCallback<T> {
    return object : MvvmHttpCallback<T>() {
    }
    }
    inline fun <reified T> newCallback(liveData: MutableLiveData<TKState<T>>): HttpCallback<TKResponse<T>> {
    val type = wrapHttpCallback<T>().getType()
    return object : HttpCallback<TKResponse<T>>(type) {
    override fun onStart() {
    liveData.value = TKState.start()
    }
    override fun onNext(response: TKResponse<T>?) {
    liveData.value = TKState.response(response)
    }
    override fun onError(e: Throwable?) {
    liveData.value = TKState.error(e)
    }
    override fun onComplete() {
    /**
    * Pro - , Don't do anything here , Don't give LiveData assignment , prevent onNext Corresponding LiveData Data is covered ,
    * stay TKState class handle Method will handle callbacks in particular , Don't worry
    */
    }
    override fun onProgress(readBytes: Long, totalBytes: Long) {
    liveData.value = TKState.progress(readBytes, totalBytes)
    }
    }
    }
    inline fun <reified T> httpGet(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance()
    .get(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    }
    inline fun <reified T> httpPost(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance().post(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    }
    inline fun <reified T> httpPostForm(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance().postForm(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    }
    inline fun <reified T> httpPut(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance().put(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    }
    inline fun <reified T> httpDelete(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance().delete(context)
    .params(params)
    .url(url)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    }
    /**
    * Upload
    * Support uploading multiple files ,map Corresponding value The type is File Type or Uri type
    * Monitor the upload progress
    val map =Map<String,Any>()
    map.put("model", "xiaomi")
    map.put("os", "android")
    map.put("avatar",File("xxx"))
    map.put("video",uri)
    */
    inline fun <reified T> httpUpload(
    context: Context,
    url: String,
    params: Map<String, Any?>?,
    tag: Any? = null
    ): MutableLiveData<TKState<T>> {
    val liveData = MutableLiveData<TKState<T>>()
    RxHttp.getInstance().upload(context)
    .url(url)
    .params(params)
    .tag(tag)
    .enqueue(newCallback(liveData))
    return liveData
    }
    /**
    * download
    * context: Context , If you don't need to bind to the lifecycle , It should be delivered applicationContext
    * url: Download address
    * dir: Local directory path
    * filename: Save the file name
    * callback: Download progress callback
    * md5: Download the file MD5 value
    * breakpoint: Whether breakpoint download is supported , The default is true
    */
    fun httpDownload(context: Context, url: String, dir: String, filename: String, callback: DownloadCallback, md5: String? = null, breakPoint: Boolean = true, tag: Any? = null) {
    RxHttp.getInstance().download(context).dir(dir).filename(filename).breakpoint(breakPoint).md5(md5).url(url).tag(tag).enqueue(callback)
    }
    }
    
    • Definition TKState class , Used to convert network callbacks to LiveData
    /**
    * take HttpCallback The callback is converted to the corresponding LiveData
    */
    class TKState<T> {
    var state: Int = 0
    var code = TKErrorCode.ERRCODE_UNKNOWN
    var msg: String? = null
    var data: T? = null
    var progress: Long = 0
    var total: Long = 0
    @JvmOverloads
    constructor(state: Int, data: T? = null, msg: String? = "") {
    this.state = state
    this.data = data
    this.msg = msg
    }
    constructor(state: Int, throwable: Throwable?) {
    this.state = state
    handleThrowable(throwable).run {
    this@TKState.code = first
    this@TKState.msg = second
    }
    }
    constructor(state: Int, progress: Long, total: Long) {
    this.state = state
    this.progress = progress
    this.total = total
    }
    fun handle(handleCallback: HandleCallback<T>.() -> Unit) {
    val callback = HandleCallback<T>()
    callback.apply(handleCallback)
    when (state) {
    START -> {
    callback.onStart?.invoke()
    }
    SUCCESS -> {
    callback.onSuccess?.invoke(data)
    }
    FAIL -> {
    callback.onFailure?.invoke(code, msg)
    }
    PROGRESS -> {
    callback.onProgress?.invoke(progress, total)
    }
    }
    if (state == SUCCESS || state == FAIL) {
    callback.onComplete?.invoke()
    }
    }
    open class HandleCallback<T> {
    var onStart: (() -> Unit)? = null
    var onSuccess: ((T?) -> Unit)? = null
    var onFailure: ((Int, String?) -> Unit)? = null
    var onComplete: (() -> Unit)? = null
    var onProgress: ((Long, Long) -> Unit)? = null
    fun onStart(callback: (() -> Unit)?) {
    this.onStart = callback
    }
    fun onSuccess(callback: ((T?) -> Unit)?) {
    this.onSuccess = callback
    }
    fun onFailure(callback: ((Int, String?) -> Unit)?) {
    this.onFailure = callback
    }
    fun onComplete(callback: (() -> Unit)?) {
    this.onComplete = callback
    }
    fun onProgress(callback: ((Long, Long) -> Unit)?) {
    this.onProgress = callback
    }
    }
    companion object {
    const val START = 0
    const val SUCCESS = 1
    const val FAIL = 2
    const val PROGRESS = 3
    fun <T> start(): TKState<T> {
    return TKState(START)
    }
    fun <T> response(response: TKResponse<T>?): TKState<T> {
    if (response != null) {
    if (response.isSuccess()) {
    return TKState(SUCCESS, response.data, null)
    } else {
    return error(ServerException(response.code, response.msg))
    }
    } else {
    return error(NullResponseException(TKErrorCode.ERRCODE_RESPONSE_NULL, TKErrorCode.ERRCODE_RESPONSE_NULL_DESC))
    }
    }
    fun <T> error(t: Throwable?): TKState<T> {
    return TKState(FAIL, t)
    }
    fun <T> progress(progress: Long, total: Long): TKState<T> {
    return TKState(PROGRESS, progress, total)
    }
    }
    }
    
    • After a series of packages , Last in View Layering as Activity in ViewModel call Repository The interface
     viewModel.testPost(hashMapOf(
    "name" to "jack",
    "location" to "shanghai",
    "age" to 28)
    )
    .observeState(this) {
    onStart {
    LogUtils.d(TAG, "onButtonPost() onStart called")
    }
    onSuccess {
    LogUtils.d(TAG, "onButtonPost() onSuccess called:${it}")
    }
    onFailure { code, msg ->
    ToastHelper.toast("onButtonPost() onFailure,code:${code},msg:${msg}")
    }
    onComplete {
    LogUtils.d(TAG, "onButtonPost() onComplete called")
    }
    }
    

    Specific use should also refer to demo Code ,demo There are detailed examples in MVVM How to use the project RxHttp

Download is highly recommended Demo Code ,Demo There are detailed examples in , demonstration MVVM And MVC How architecture is used RxHttp, If this article helps you , You can think about giving me some praise

Demo

https://github.com/kongpf8848/RxHttp

版权声明
本文为[Antarctic glacier snow]所创,转载请带上原文链接,感谢
https://qdmana.com/2021/02/20210223130333251r.html

  1. 对前端异常window error捕获的全面总结
  2. A comprehensive summary of front end exception window error capture
  3. 成功解决Problem while trying to mount target]\“. HTTP response code is 400
  4. Problem while trying to mount target] \ ". HTTP response code is 400
  5. 放弃okhttp、httpClient,选择了这个牛逼的神仙工具!贼爽
  6. 前端面试每日 3+1 —— 第679天
  7. How to add elements at the beginning of an array in JS?
  8. Give up okhttp and httpclient and choose this awesome immortal tool! Thief Shuang
  9. Front end interview daily 3 + 1 - day 679
  10. 【2021 第一期】日常开发 26 个常见的 JavaScript 代码优化方案
  11. Daily development of 26 common JavaScript code optimization schemes
  12. 前端的字符串时间如何自动转换为后端Java的Date属性,介绍springMVC中如何解决时间转换问题
  13. How to automatically convert the front-end string time to the back-end Java date attribute, and how to solve the time conversion problem in spring MVC are introduced
  14. 前端面试常考题:JS垃圾回收机制
  15. ReactDOM.render串联渲染链路(一)
  16. 更简洁、更快速!腾讯云 Serverless 云函数创建流程再次升级!
  17. 粗涉Webpack
  18. Frequently asked questions in front end interview: JS garbage collection mechanism
  19. ReactDOM.render Serial rendering link (1)
  20. More concise and faster! Tencent cloud serverless cloud function creation process upgrade again!
  21. 更简洁、更快速!腾讯云 Serverless 云函数创建流程再次升级!
  22. About webpack
  23. More concise and faster! Tencent cloud serverless cloud function creation process upgrade again!
  24. 详解vue静态资源打包中的坑与解决方案
  25. 一篇搞懂TCP、HTTP、Socket、Socket连接池
  26. 字节跳动2021前端技术岗发布+最新内部面试题
  27. Detailed explanation of Vue static resource packaging and Solutions
  28. Understanding TCP, HTTP, socket, socket connection pool
  29. 2008-2021 front end technical post release + latest internal interview questions
  30. 4. Vue基本指令
  31. 4. Vue basic instruction
  32. Java 发起 http 请求
  33. Java initiates HTTP request
  34. 网站由http升级为https图文教程
  35. Upgrade the website from HTTP to HTTPS
  36. 更简洁、更快速!腾讯云 Serverless 云函数创建流程再次升级!
  37. More concise and faster! Tencent cloud serverless cloud function creation process upgrade again!
  38. 混合开发入门 Vue结合Android/iOS开发仿京东项目App
  39. Hybrid development entry Vue combined with Android / IOS to develop app imitating Jingdong project
  40. 无缝对接 Tableau,这家月活跃用户 5000+ 的大型银行如何实现自助式分析?
  41. Are airpods still the strongest? Horizontal evaluation of 4 true wireless headphones
  42. Seamless connection with tableau, how can this large bank with 5000 + active users realize self-service analysis?
  43. react-native版文字跑马灯
  44. React native text running lantern
  45. Java、JavaScript、C、C++、PHP、Python都是用来开发什么?
  46. What are Java, JavaScript, C, C + +, PHP and python used to develop?
  47. this.byId(SupplierForm).bindElement in SAP UI5
  48. SAP UI5 JavaScript文件的lazy load - 懒加载
  49. this.byId (SupplierForm).bindElement in SAP UI5
  50. Lazy load lazy load of SAP ui5 JavaScript files
  51. "Gnome 3" - interface elements, desktop components, part names (learning notes) @ 20210223
  52. How to connect the ground gas to the micro front end?
  53. How to transform single / micro service application into serverless application
  54. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法
  55. Seven array methods for JavaScript you need to master in 2021
  56. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法
  57. Seven array methods for JavaScript you need to master in 2021
  58. 在 2021 年你需要掌握的 7 种关于 JavaScript 的数组方法
  59. Seven array methods for JavaScript you need to master in 2021
  60. RxHttp - 轻量级、可扩展、易使用、完美兼容MVVM、MVC架构的网络封装类库