从0开始封装一套项目的网络请求框架

从0开始封装一套项目的网络请求框架,第1张

前言

Android进行网络请求,一般是通过Retrofit配合RxJava来实现。需要注意的是,在项目中,是不可能直接在每一个请求的地方直接裸着用框架,而是一定在自己的项目中对框架封装了一层,实际使用的是封装的这一层。
本篇文章就来介绍一种封装方案,在项目中可以使用。此方案肯定有不足的地方,还请批评指正。

用到的知识

Kotlin、Retrofit,RxJava,OkHttp

步骤介绍 1.api介绍

在这里使用鸿洋大神的开放api,链接点这里。只使用登录api即可,其他的api都是一样的方式。

url:https://www.wanandroid.com/user/login
方法:POST
参数:username,password

这里推荐一款很好用的接口测试工具Apipost,我这边测试一下登录的接口

它返回的response由三部分组成,分别是data,errorCode,errorMsg。我把结果粘贴过来

{
	"data": {
		"admin": false,
		"chapterTops": [],
		"coinCount": 10,
		"collectIds": [],
		"email": "",
		"icon": "",
		"id": 130077,
		"nickname": "LJH111",
		"password": "",
		"publicName": "LJH111",
		"token": "",
		"type": 0,
		"username": "LJH111"
	},
	"errorCode": 0,
	"errorMsg": ""
}
2.创建项目

创建一个kotlin项目,完成必要的准备
①依赖导入
在app模块的gradle文件中导入retrofit和rxjava的依赖

//导入retrofit
implementation 'com.squareup.retrofit2:retrofit:2.3.0'
implementation 'com.squareup.retrofit2:converter-gson:2.3.0'//ConverterFactory的Gson依赖包
implementation 'com.squareup.retrofit2:converter-scalars:2.3.0'//ConverterFactory的String依赖包
implementation("com.squareup.okhttp3:okhttp:4.9.1")
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.3.0'

//导入rxjava
compile 'io.reactivex.rxjava2:rxandroid:2.0.1'
compile "io.reactivex.rxjava2:rxjava:2.0.8"

②开启网络权限
(1)首先新建一个xml文件,如图

内容是

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true" />
</network-security-config>

(2)然后找到Menifest文件
在application标签中设置这样的属性

(3)然后,在menifest中打开网络权限

内容为

<!--网络权限-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
3.新建response模板类

所有的response都有一个共性,即由三部分组成,分别是data,errorCode,errorMsg。这里只有data的类型不确定,但是可以用泛型表示。
所以可以用一个通用的模板类来接收所有的Response

/**
 * Created by didiwei on 2022/4/20
 * desc: 所有请求的模板类
 */
data class ResponseModel<T>(val data: T,
                         val errorCode: String?,
                         val errorMsg: String?)

data用泛型表示即可

4.新建登录成功时,返回的data模板类

登录成功时,返回的json如下

{
	"data": {
		"admin": false,
		"chapterTops": [],
		"coinCount": 10,
		"collectIds": [],
		"email": "",
		"icon": "",
		"id": 130077,
		"nickname": "LJH111",
		"password": "",
		"publicName": "LJH111",
		"token": "",
		"type": 0,
		"username": "LJH111"
	},
	"errorCode": 0,
	"errorMsg": ""
}

其中因为data是不同的api,可能会不一样,所以最好用一个类来区分不同的data。这里登录成功时,返回的data我这样表示

/**
 * Created by didiwei on 2022/4/20
 * desc: 登录成功时,返回的response中的data的模板类
 */
data class LoginSuccessResData(val admin: Boolean,
                               val chapterTops: List<*>,
                               val coinCount: Int,
                               val collectIds: List<*>,
                               val email: String?,
                               val icon: String?,
                               val id: String?,
                               val nickname: String?,
                               val password: String?,
                               val publicName: String?,
                               val token: String?,
                               val type: Int,
                               val username: String?)
5.自定义RxJava *** 作符

正常的逻辑应该是这样的,请求成功时,把data丢给UI,请求失败时,把errorMsg丢给UI。所以我们可以自定义RxJava *** 作符,当数据返回时,对Response完成这样的功能。

/**
 * Created by didiwei on 2022/4/20
 * desc: RxJava的自定义 *** 作符,用于剥离data和errorMsg
 */
abstract class RxJavaInterceptor<T> : Observer<ResponseModel<T>> {
    abstract fun success(data: T?)
    abstract fun failure(errorMsg: String?)

    override fun onSubscribe(d: Disposable?) {
        //这里可以弄个加载dialog的start,别忘了在请求结束(不管成功还是失败)的时候让这个dialog消失
    }

    override fun onNext(t: ResponseModel<T>?) {
        if(t?.data != null){
            //请求成功了
            success(t?.data)
        }else{
            //失败
            failure(t?.errorMsg)
        }
    }

    override fun onError(e: Throwable?) {
        failure(e?.message)
    }

    override fun onComplete() {
        //可以加个dialog的消失
    }

}

有个注意点,首先RxJavaInterceptor类为抽象类,里面的successfailure为抽象方法,当调用的时候实现。其次是这里依然是泛型类,适用于各个model

6.写请求的接口
/**
 * Created by didiwei on 2022/4/20
 * desc: 关于用户登录 注册的api
 */
interface UserService {
    /**
     * desc 登录的接口
     *
     * url:https://www.wanandroid.com/user/login
     * 方法:POST
     * 参数:username,password
     */
    @POST("/user/login")
    @FormUrlEncoded
    fun loginAction(@Field("username")username: String?,
                    @Field("password")password: String?)
        :Observable<ResponseModel<LoginSuccessResData>>
}

注意它的返回值是Observable类型,作为被观察者,流向观察者(RxJava的知识)

7.创建实例化service的类
/**
 * Created by didiwei on 2022/4/20
 * desc: 此类是单例类,用于创建Service的实例
 */
class ApiClient {
    private object Holder{
        val instance = ApiClient()
    }

    companion object{
        val INSTANCE = Holder.instance
    }

    fun <T> createRetrofit(retrofitInterface: Class<T>) : T{
        //创建okhttp
        val mOkHttpClient = OkHttpClient().newBuilder()
            .readTimeout(10000, TimeUnit.SECONDS)//读取超时时间
            .connectTimeout(10000, TimeUnit.SECONDS)//连接超时时间
            .writeTimeout(10000, TimeUnit.SECONDS)//写出超时时间
            .build()

        //创建retrofit
        val retrofit: Retrofit = Retrofit.Builder()
            .baseUrl("https://www.wanandroid.com")
            .client(mOkHttpClient)
            .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
            .addConverterFactory(GsonConverterFactory.create())
            .build()
        
        //返回
        return retrofit.create(retrofitInterface)
    }
}
8.这样当我们使用的时候,就可以这样用

比如添加一个登录按钮,然后注册其点击事件

class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val userLoginBtn: Button = findViewById<Button>(R.id.userLoginBtn)
        userLoginBtn.setOnClickListener(onClickListener)
    }

    private val onClickListener = View.OnClickListener {
        when(it.id){
            R.id.userLoginBtn ->{
                val userName = "LJH111"
                val userPwd = "123456"

                ApiClient.INSTANCE.createRetrofit(UserService::class.java)
                        .loginAction(userName,userPwd)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(object : RxJavaInterceptor<LoginSuccessResData>(){
                            override fun success(data: LoginSuccessResData?) {
                                Log.v("ljh","请求成功,返回的data为:${data}")
                            }

                            override fun failure(errorMsg: String?) {
                                Log.v("ljh","请求失败,错误信息为:${errorMsg}")
                            }
                        })
            }
        }
    }
}

效果

如果改成错误的用户名或密码,效果是这样的

至此,我们就完成了网络请求规则的封装

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/989855.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-21
下一篇 2022-05-21

发表评论

登录后才能评论

评论列表(0条)

保存