Retrofit+RxJava配置访问网络

  1. Android网络框架使用过的包括HttpClient,HttpURLConnection,Volley,OKhttp等等,OKhttp是现在常用的用于网络访问的框架。
  2. 现在常常开发中是Okhttp配合Retrofit和RxJava一起使用,单独显得更加优雅。
  3. 本文就介绍下这三个配合使用,现在Retrofit默认就是使用的OKhttp作为网络访问框架。下次可以把OKhttp单独使用写一下。
封装库放在github

RxJava、Retrofit配合网络访问的封装库
感兴趣的可以直接去下载使用

Retrofit

简单介绍下Retrofit的使用,直接使用的官网 1 的例子

  1. 官网例子简单了解下整个接口请求流程
1、定义访问服务器接口的接口文件
public interface GitHubService {
  // 一个简单的get请求接口,Retrofit中使用@GET注解表示get请求
  // 下面这个接口定义是返回一个Repo对象的List集合,{user}表示将请求参数填充在链接的此处
  @GET("users/{user}/repos")
  Call> listRepos(@Path("user") String user);
}

2、创建Retrofit对象
// 获取Retrofit对象,拼接接口的公有地址
Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("https://api.github.com/")
    .build();

3、获取接口对象
// 获取网络访问接口对象
GitHubService service = retrofit.create(GitHubService.class);

4、调用接口请求服务器数据,到这里整个网络访问流程就走完了
Call> repos = service.listRepos("octocat");
  1. 简单介绍下常用网络访问方法
GET请求
1、group/{id}/users次数的{id}表示将@Path修饰的参数插入这里
@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId);

2、@Query("sort")表示根据sort这个参数到服务器去查询数据,就是我们平常访问接口的查询条件
@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId, @Query("sort") String sort);

3、@QueryMap Map,表示使用Map插入一组查询条件,不用我们每个查询条件都去写一次
例如这种:
@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId, @Query("sort") String sort,, @Query("age") int age);
或者更多的参数,我们就可以使用@QueryMap注解去修饰,然后传入我们需要给服务器的请求参数结合。使用方式如下
@GET("group/{id}/users")
Call> groupList(@Path("id") int groupId, @QueryMap Map options);
POST请求
1、我们常用的使用json对象访问接口,@Body修饰我们上传的参数对象
@POST("users/new")
Call createUser(@Body User user);

2、使用表单上传参数,@Field修饰post请求的参数,如果参数过多Retrofit依然给我们
准备了跟get请求一样的上传多个参数的map注解@FieldMap,将请求参数封装成Map集合
@FormUrlEncoded
@POST("user/edit")
Call updateUser(@Field("first_name") String first, @Field("last_name") String last);

3、使用表单进行文件上传,@Part,@PartMap用于表单字段,适用于有文件上传的情况
@Multipart
@PUT("user/photo")
Call updateUser(@Part("photo") RequestBody photo, @Part("description") RequestBody description);

文件上传后面再详细讲解,请往后看。
  1. 介绍常用的注解
类型 注解 作用
@POST
@GET
@PUT
网络请求方法 @DELETE 对应HTTP请求中的所有方法,都指定接收一个网络地址
@PATH
@HEAD
@OPTIONS
@HTTP 用来替换上面七个注解,以及更多的功能

例如:

post或者其他请求的使用
@POST("file/batch/upload")

但是@HTTP的使用,指定请求方法,请求路径,指定是都包含Body请求体
@HTTP(method = "GET",path = "")
@HTTP(method = "GET",path = "",hasBody = true)
注解 作用
@FormUrlEncoded POST请求,标记为表单请求
@Multipart 标记支持表单类型的文件上传
@Streaming 表示以流的形式返回数据,返回数据较大的场景,一般用于文件下载
注解 作用
@Headers 添加在方法上固定的请求头
@Header 将请求头作为请求参数,动态添加单个请求头
@HeaderMap 动态添加一组请求头
@Body 修饰非表单请求,我们常用的使用json对象请求接口
@Field post表单请求,添加一个请求参数
@FieldMap post表单请求,添加一组请求参数
@Query get请求使用的表单字段,表示添加一个请求参数
@QueryMap get请求使用的表单字段,表示添加一组请求参数
@Path URL缺省值
@Url 传入整个URL

例如

1、@Url注解的使用,没在@GET请求传递URL地址,而是全部通过动态传入
@Streaming
@GET
fun download(@Url url: String): Observable

2、@Path修饰的参数,是填充到@GET({"study/{id}"})链接中{}修饰的链接处
@Streaming
@GET("{name}")
fun download1(@Path("name") name:String): Observable

3、下面这两种就是添加固定的一个或多个请求头的方式
@Headers("Cache-Control: max-age=640000")
@GET("widget/list")
Call> widgetList();

@Headers({
    "Accept: application/vnd.github.v3.full+json",
    "User-Agent: Retrofit-Sample-App"
})
@GET("users/{username}")
Call getUser(@Path("username") String username);

4、下面就是动态添加一个或一组请求头的方式
@GET("user")
Call getUser(@Header("Authorization") String authorization)

@GET("user")
Call getUser(@HeaderMap Map headers)

RxJava+Retrofit配合使用

整个我使用的库的封装,我就懒得贴代码了,是真的太多了,贴上大家看着也烦,O(∩_∩)O哈哈~,我会把代码放在github上,有兴趣的可以下载来看看。

代码中我已经写得很清楚了,具体是干什么的,请求库我会放在github,调用的代码就参考下面的使用,我就没有去写例子了,直接从我写的项目中抽出来的。

  1. 首先导入需要的库
implementation 'io.reactivex.rxjava2:rxjava:2.2.4'
// 线程的切换
implementation 'io.reactivex.rxjava2:rxandroid:2.1.0'
implementation 'com.squareup.retrofit2:retrofit:2.5.0'
// 可以直接将json字符串返回回来
implementation 'com.squareup.retrofit2:converter-scalars:2.5.0'
// 返回Gson解析之后的对象
implementation 'com.squareup.retrofit2:converter-gson:2.5.0'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.5.0'
implementation 'com.squareup.okhttp3:okhttp:3.12.0'
  1. 看一下具体的使用
  • GET请求,因为整体是使用的MVP,所以此处只是简单地把代码抽出来了,但是不影响具体的调用,这里是没问题的。
// 定义请求接口,Observable是RxJava中的操作符
@GET("${BaseHost.CORE}fx/area/sparkAreaList")
fun getSparkAreaList(@Query("fId") fId: Int): Observable>>

// 具体的调用,还是很简洁的
RetrofitManager
            .instance // 获取RetrofitManager对象
            .createService(ApiService::class.java) // 获取接口对象
            .getSparkAreaList(fId) // 调用接口
            .compose(SelfTransformer()) // 封装了线程切换的共有操作
            .subscribe(SelfObserver(object : NetCallBack> { // 封装了数据的解析
                override fun onSubscribe(disposable: Disposable) {

                }

                override fun onSuccess(t: MutableList) {
                    areaListener.onSuccess(t)
                }

                override fun onError(exception: ApiException) {
                    areaListener.onError(exception)
                }
            }))
  • post请求
// 表单类型的Post请求,这里返回值是直接返回Gson解析出来的对象
@FormUrlEncoded
@POST("user/login")
fun loginMap(@FieldMap map: MutableMap): Observable>

// 具体的调用,其实跟get没有多大差别
RetrofitManager
            .instance
            .createService(ApiService::class.java)
            .loginMap(map)
            .compose(SelfTransformer())
            .subscribe(SelfObserver(object : NetCallBack {
                override fun onSubscribe(disposable: Disposable) {

                }

                override fun onSuccess(user: User) {
                    userListener.onSuccess(user)
                }

                override fun onError(exception: ApiException) {
                    userListener.onError(exception)
                }
            }))
// 请求对象类型的,直接返回服务器告诉我们的json字符串
fun updateAd(@HeaderMap headMap: MutableMap, @Body updateProjectReq: UpdateProjectReq): Observable

// 这里的处理方式可以对比上面的代码,直接使用服务器返回的json我们自己做了单独的处理,这里我的参考代码也会放在github,有兴趣的可以下载下来看
RetrofitManager
            .instance
            .createService(ApiService::class.java)
            .updateAd(headMap, updateProjectReq)
            .map(HttpResultFunc1())
            .compose(SelfTransformer1())
            .subscribe(SelfObserver1(object : NetCallBack {
                override fun onSubscribe(disposable: Disposable) {

                }

                override fun onSuccess(t: BaseDataF) {
                    updateAdListener.onSuccess(t)
                }

                override fun onError(exception: ApiException) {
                    updateAdListener.onError(exception)
                }
            }))
  • 文件下载
// 此处我自己使用的文件下载,直接传入下载链接用@Url修饰,@Streaming表示以流的形式返回
@Streaming
@GET
fun download(@Url url: String): Observable

// 具体的使用,具体的下载拦截管理之类的封装,去查看DownRetrofitManager,这里就是完整的处理逻辑,在ProgressListener 中处理下载进度
DownRetrofitManager
            .instance
            .createService(ApiService::class.java, object : ProgressListener {
                @SuppressLint("SetTextI18n")
                override fun onProgress(bytesRead: Long, contentLength: Long, done: Boolean) {
                    LogUtils.d("DownloadDialog", "当前进度;$bytesRead==>总的进度:$contentLength==>是否完成:$done")
                    isDownComplete = done
                    val progress = ((bytesRead.toFloat() / contentLength.toFloat()) * 100).toInt()
                    activity.runOnUiThread {
                        progressBar?.progress = progress
                        tvSize?.text = String.format(
                            activity.getString(R.string.down_size),
                            FileUtils.formatSize(bytesRead),
                            FileUtils.formatSize(contentLength)
                        )
                        tvRatio?.text = "$progress%"
                        LogUtils.d("DownloadDialog", "进度$progress")
                    }
                }
            })
            .download(downUrl)
            .map(DownResultFunc())
            .subscribeOn(Schedulers.io())
            .unsubscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Observer {
                override fun onComplete() {

                }

                override fun onSubscribe(d: Disposable) {
                    disposable = d
                }

                override fun onNext(t: InputStream) {
                    FileUtils.writeFileFromIs(downPath, t)
                }

                override fun onError(e: Throwable) {
                    ToastUtils.showShort(activity, e.message.toString())
                }

            })
  • 文件上传
    文件上传下载直接使用OKhttp其实更简单
//@Multipart
@POST("${BaseHost.BUSINESS}learn/batch")
fun uploadImg(@HeaderMap headMap: MutableMap, @Body requestBody: RequestBody): Observable>>

// 参数封装
val builder: MultipartBody.Builder = MultipartBody.Builder()
            for (file in files) {
                val requestBody = RequestBody.create(MediaType.parse("application/octet-stream"), file)
                //val requestBody = RequestBody.create(MediaType.parse("application/form-data;charset=utf-8"), file)
                val progressBody = ProgressRequestBody(requestBody, progressListener)
                // 如下两个参数的封装,是跟服务器定义的两个参数
                builder.addFormDataPart("type", Constants.UPLOAD_IMG_COVER)
                // 解决文件名为中文,程序崩溃,在获取到文件名的时候记得解码
                builder.addFormDataPart("file", URLEncoder.encode(file.name, "UTF-8"), progressBody)
            }

下面调用的.uploadImg(headMap, requestBody),requestBody = builder.build()

// 具体调用
RetrofitManager
            .instance
            .createService(ApiService::class.java)
            .uploadImg(headMap, requestBody)
            .compose(SelfTransformer())
            .subscribe(SelfObserver(object : NetCallBack> {
                override fun onSubscribe(disposable: Disposable) {

                }

                override fun onSuccess(t: MutableList) {
                    uploadListener.onSuccess(t)
                }

                override fun onError(exception: ApiException) {
                    uploadListener.onError(exception)
                }

            }))

参考


  1. https://square.github.io/retrofit/ ↩︎

你可能感兴趣的:(Android学习总结,kotlin,android)