热门标签 | HotTags
当前位置:  开发笔记 > 前端 > 正文

Kotlin+Retrofit+RxJava简单封装使用详解

这篇文章主要介绍了Kotlin+Retrofit+RxJava简单封装使用详解,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

本文介绍了Kotlin + Retrofit + RxJava简单封装使用详解,分享给大家,具体如下:

实例化Retrofit

object RetrofitUtil {

  val CONNECT_TIME_OUT = 30//连接超时时长x秒
  val READ_TIME_OUT = 30//读数据超时时长x秒
  val WRITE_TIME_OUT = 30//写数据接超时时长x秒

  val retrofit: Retrofit by lazy {
    Log.d("RetrofitUtil", "retrofit init lazy")
    Retrofit.Builder()
        .baseUrl("http://gank.io/api/")  //本文以GitHub API为例
        .addConverterFactory(GsonConverterFactory.create())
        .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
        .client(getOkHttpClient())
        .build()
  }

  private fun getOkHttpClient(): OkHttpClient {
    val builder = OkHttpClient.Builder()
    builder.connectTimeout(CONNECT_TIME_OUT.toLong(), TimeUnit.SECONDS)
        .writeTimeout(WRITE_TIME_OUT.toLong(), TimeUnit.SECONDS)
        .readTimeout(READ_TIME_OUT.toLong(), TimeUnit.SECONDS)
    if (BuildConfig.DEBUG) {
      builder.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.BODY))
    } else {
      builder.addInterceptor(HttpLoggingInterceptor().setLevel(HttpLoggingInterceptor.Level.NONE))
    }
    // 设置请求头
    builder.addInterceptor { chain ->
      val time = (System.currentTimeMillis() / 1000).toString() + ""
      val requestBuilder = chain.request().newBuilder()
      requestBuilder.addHeader("time", time)
      chain.proceed(requestBuilder.build())
    }
    return builder.build()
  }
}

返回数据封装

class Response {
  var error: Boolean = false
  var results: T? = null
}

demo中用了gank.io的开发api,之前一般项目的返回格式是code + message + T的格式。

api接口错误/异常统一处理类

class ApiException : Exception {
  var code: Int = 0//错误码
  var msg: String? = null//错误信息

  constructor(throwable: Throwable, code: Int) : super(throwable) {
    this.code = code
  }

  constructor(code: Int, msg: String) {
    this.code = code
    this.msg = msg
  }
}

定义ExceptionFunction处理onErrorResumeNext:

class ExceptionFunction : Function> {
  override fun apply(@NonNull throwable: Throwable): Observable {
    Log.e("ExceptionFunction", throwable.message)
    return Observable.error(ExceptionEngine().handleException(throwable))
  }
}

/**
 * 错误/异常处理工具
 */
class ExceptionEngine {

  val UN_KNOWN_ERROR = 1000//未知错误
  val ANALYTIC_SERVER_DATA_ERROR = 1001//解析(服务器)数据错误
  val CONNECT_ERROR = 1002//网络连接错误
  val TIME_OUT_ERROR = 1003//网络连接超时

  fun handleException(e: Throwable): ApiException {
    val ex: ApiException
    if (e is ApiException) {  //服务器返回的错误
      return e
    } else if (e is HttpException) {       //HTTP错误
      ex = ApiException(e, e.code())
      ex.msg = "网络错误:" + ex.code
      return ex
    } else if (e is JsonParseException
        || e is JSONException
        || e is ParseException || e is MalformedJsonException) { //解析数据错误
      ex = ApiException(e, ANALYTIC_SERVER_DATA_ERROR)
      ex.msg = "解析错误"
      return ex
    } else if (e is ConnectException) {//连接网络错误
      ex = ApiException(e, CONNECT_ERROR)
      ex.msg = "连接失败"
      return ex
    } else if (e is SocketTimeoutException) {//网络超时
      ex = ApiException(e, TIME_OUT_ERROR)
      ex.msg = "网络超时"
      return ex
    } else { //未知错误
      ex = ApiException(e, UN_KNOWN_ERROR)
      ex.msg = e.message
      return ex
    }
  }
}

封装请求处理

object Rx {

  /**
   * Rxlifecycle绑定生命周期
   */
  fun  get(observable: Observable>, lifecycleProvider: LifecycleProvider): Observable {

    // 请求绑定生命周期,防止内存泄漏,同时返回回调之后页面已销毁造成的空指针错误
    if (lifecycleProvider is RxAppCompatActivity) {
      val rxAppCompatActivity = lifecycleProvider as RxAppCompatActivity
      observable.compose(rxAppCompatActivity.bindUntilEvent(ActivityEvent.DESTROY))
    } else if (lifecycleProvider is RxFragment) {
      val rxFragment = lifecycleProvider as RxFragment
      observable.compose(rxFragment.bindUntilEvent(FragmentEvent.DESTROY))
    }

    return observable
        .compose(HandleResult())
        .onErrorResumeNext(ExceptionFunction())
  }

  /**
   * 部分后台请求
   */
  fun  get(observable: Observable>): Observable {

    return observable
        .compose(HandleResult())
        .onErrorResumeNext(ExceptionFunction())
  }

  private class HandleResult : ObservableTransformer, T> {
    override fun apply(upstream: Observable>): ObservableSource {
      return upstream.flatMap { response -> createResult(response) }
          .subscribeOn(Schedulers.io())
          .unsubscribeOn(Schedulers.io())
          .observeOn(AndroidSchedulers.mainThread())
    }
  }

  private fun  createResult(response: Response): Observable {
    return Observable.create({ subscriber ->
      if (response.error)
        throw ApiException(-1, "服务器异常") // 一般来说,自己的服务器异常会返回相应的code和message
      else
        response.results?.let {
          subscriber.onNext(response.results!!)
        } ?: subscriber.onComplete()
    })
  }

}

定义HttpObserver统一处理返回

abstract class HttpObserver : Observer {

  /**
   * 标记是否为特殊情况
   */
  private var resultNull: Boolean = true

  override fun onComplete() {
    // 特殊情况:当请求成功,但T == null时会跳过onNext,仍需当成功处理
    if (resultNull)
      onSuccess(null)
  }

  override fun onSubscribe(d: Disposable) {
    // 可在此处加上dialog
  }

  override fun onError(e: Throwable) {
    if (e is ApiException) {
      onError(e.code, e.msg)
    } else {
      onError(0, e.message)
    }
  }

  override fun onNext(t: T) {
    resultNull = false
    onSuccess(t)
  }

  abstract fun onSuccess(t: T?)

  /**
   * 统一处理失败,比如登录失效等
   *
   * @param code
   * @param msg
   */
  open fun onError(code: Int, msg: String?) {

  }

}

Api

class Result {
  var _id: String? = null
  var createdAt: String? = null
  var desc: String? = null
  var publishedAt: String? = null
  var source: String? = null
  var type: String? = null
  var url: String = ""
  var isUsed: Boolean = false
  var who: String? = null
  var images: List? = null
  /**
   * 妹子小图
   */
  fun meiziSmallUrl(): String {
    val meizi = url
    return meizi.replace("large", "small")
  }
}

interface Apiservice {
  @GET("data/{type}/10/{page}")
  fun getGank(@Path("type") type: String, @Path("page") page: Int): Observable>>
}

object Api {
  val apiservice: Apiservice by lazy {
    Log.d("Api", "apiservice create lazy")
    RetrofitUtil.retrofit.create(Apiservice::class.java)
  }
}

使用

override fun loadData() {
    Rx.get(Api.apiservice.getGank(getType(), mIntPage), this).subscribe(object : HttpObserver>() {
      override fun onSuccess(t: List?) {
        //getDataSuccess(t)
      }

      override fun onError(code: Int, msg: String?) {
        super.onError(code, msg)
        //getDataFailed()
      }
    })
  }

使用了Rxlifecycle绑定生命周期来处理可能发生的内存泄漏问题,Fragment跟Activity需要继承Rx相应的基类。

练手项目

Meizikt Gank.io Android客户端,使用Kotlin + Retrofit2 + RxJava

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。


推荐阅读
  • 本文介绍了在开发Android新闻App时,搭建本地服务器的步骤。通过使用XAMPP软件,可以一键式搭建起开发环境,包括Apache、MySQL、PHP、PERL。在本地服务器上新建数据库和表,并设置相应的属性。最后,给出了创建new表的SQL语句。这个教程适合初学者参考。 ... [详细]
  • Centos7.6安装Gitlab教程及注意事项
    本文介绍了在Centos7.6系统下安装Gitlab的详细教程,并提供了一些注意事项。教程包括查看系统版本、安装必要的软件包、配置防火墙等步骤。同时,还强调了使用阿里云服务器时的特殊配置需求,以及建议至少4GB的可用RAM来运行GitLab。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • baresip android编译、运行教程1语音通话
    本文介绍了如何在安卓平台上编译和运行baresip android,包括下载相关的sdk和ndk,修改ndk路径和输出目录,以及创建一个c++的安卓工程并将目录考到cpp下。详细步骤可参考给出的链接和文档。 ... [详细]
  • 安卓select模态框样式改变_微软Office风格的多端(Web、安卓、iOS)组件库——Fabric UI...
    介绍FabricUI是微软开源的一套Office风格的多端组件库,共有三套针对性的组件,分别适用于web、android以及iOS,Fab ... [详细]
  • 本文介绍了Hyperledger Fabric外部链码构建与运行的相关知识,包括在Hyperledger Fabric 2.0版本之前链码构建和运行的困难性,外部构建模式的实现原理以及外部构建和运行API的使用方法。通过本文的介绍,读者可以了解到如何利用外部构建和运行的方式来实现链码的构建和运行,并且不再受限于特定的语言和部署环境。 ... [详细]
  • 使用在线工具jsonschema2pojo根据json生成java对象
    本文介绍了使用在线工具jsonschema2pojo根据json生成java对象的方法。通过该工具,用户只需将json字符串复制到输入框中,即可自动将其转换成java对象。该工具还能解析列表式的json数据,并将嵌套在内层的对象也解析出来。本文以请求github的api为例,展示了使用该工具的步骤和效果。 ... [详细]
  • 关于我们EMQ是一家全球领先的开源物联网基础设施软件供应商,服务新产业周期的IoT&5G、边缘计算与云计算市场,交付全球领先的开源物联网消息服务器和流处理数据 ... [详细]
  • 本文介绍了高校天文共享平台的开发过程中的思考和规划。该平台旨在为高校学生提供天象预报、科普知识、观测活动、图片分享等功能。文章分析了项目的技术栈选择、网站前端布局、业务流程、数据库结构等方面,并总结了项目存在的问题,如前后端未分离、代码混乱等。作者表示希望通过记录和规划,能够理清思路,进一步完善该平台。 ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Google Play推出全新的应用内评价API,帮助开发者获取更多优质用户反馈。用户每天在Google Play上发表数百万条评论,这有助于开发者了解用户喜好和改进需求。开发者可以选择在适当的时间请求用户撰写评论,以获得全面而有用的反馈。全新应用内评价功能让用户无需返回应用详情页面即可发表评论,提升用户体验。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
  • 使用正则表达式爬取36Kr网站首页新闻的操作步骤和代码示例
    本文介绍了使用正则表达式来爬取36Kr网站首页所有新闻的操作步骤和代码示例。通过访问网站、查找关键词、编写代码等步骤,可以获取到网站首页的新闻数据。代码示例使用Python编写,并使用正则表达式来提取所需的数据。详细的操作步骤和代码示例可以参考本文内容。 ... [详细]
  • 在Android中解析Gson解析json数据是很方便快捷的,可以直接将json数据解析成java对象或者集合。使用Gson解析json成对象时,默认将json里对应字段的值解析到java对象里对应字段的属性里面。然而,当我们自己定义的java对象里的属性名与json里的字段名不一样时,我们可以使用@SerializedName注解来将对象里的属性跟json里字段对应值匹配起来。本文介绍了使用@SerializedName注解解析json数据的方法,并给出了具体的使用示例。 ... [详细]
author-avatar
梦蕾AngeL
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有