02Kotlin项目实操之Retrofit网络模型
Posted 清风百草
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了02Kotlin项目实操之Retrofit网络模型相关的知识,希望对你有一定的参考价值。
(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)好好活就是做有意义的事情.
(8)亡羊补牢,为时未晚
(9)科技领域,没有捷径与投机取巧。
(10)有实力,一年365天都是应聘的旺季,没实力,天天都是应聘的淡季。
(11)基础不牢,地动天摇
(12)写博客初心:成长自己,辅助他人。当某一天离开人世,希望博客中的思想还能帮人指引方向.
(13)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~
Kotlin项目实战之Retrofit网络模型
Kotlin体系文档
1.项目实战的目的是什么?
了解用Kotlin来开发项目的过程
2.Retrofit网络模型
2.1请求服务器的模型封装,登录使用网络模型
2.1.1客户端登录API接口定义
import com.gdc.kotlinproject.entity.LoginResponse
import com.gdc.kotlinproject.entity.LoginResponseWrapper
import io.reactivex.Observable
import retrofit2.http.Field
import retrofit2.http.FormUrlEncoded
import retrofit2.http.POST
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.kotlinproject.api
* @file
* @Description:
*
* 1.客户端API,可以访问服务器端API
*
* 1.1请求接口路径
* 1.2请求参数
* 1.3请求数据响应实体
*
* 1.3.1LoginResponseWrapper包装bean
* 1.3.2LoginResponse:数据bean
*
* @date 2021-5-2 16:02
* @since appVer
*/
interface WanandroidAPI {
/**
* 登录API
* username=Derry-vip&password=123456
*/
@POST("/user/login")
@FormUrlEncoded
fun loginAction(@Field("username") username: String,
@Field("password") password: String)
: Observable<LoginResponseWrapper<LoginResponse>>
/**
* 注册API
*/
}
2.1.2登录响应实体封装
(1)分为数据实体与错误码相关信息
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.kotlinproject.entity
* @file
* @Description:1.登录数据响应实体
* (1)登录数据实体
* (2)因为不知道数据实体中data是什么类型,有可能为空或者有数据,所以将其定义为泛型,可以随用户的传递而传递
* (3)errorCode,errorMsg是具体的
* @date 2021-5-2 16:37
* @since appVer
*/
data class LoginResponseWrapper<T>(val data:T,val errorCode:Int,val errorMsg:String) {
}
2.1.2 响应实体中数据实体的封装
/**
* 1.data 登录成功 需要把这个Bean 给 UI
"data": {
"admin": false,
"chapterTops": [],
"collectIds": [],
"email": [],
"icon": "",
"id": 66720,
"nickname": "Derry-vip",
"password": "",
"publicName": "Derry-vip",
"token": "",
"type": 0,
"username": "Derry-vip"
}
2.泛型通配符Kotlin中使用的是*,java中使用的是?
3.为什么email的String类型后还加一个?
3.1是因为,如果email的值为null的话,不添加?很可能导致序列化进来的数据失败。
3.1?的作用就是允许该值为null
*/
data class LoginResponse(
val admin:Boolean,
val chapterTops : List<*>,
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?) {
}
3.对应用请求响应API接口的统一管理
import okhttp3.OkHttpClient
import retrofit2.Retrofit
import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory
import retrofit2.converter.gson.GsonConverterFactory
import java.util.concurrent.TimeUnit
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.kotlinproject.net
* @file
* @Description:
* 1.对应用请求响应API接口的统一管理
* 即对每一个请求与响应进行统一管理
*
* 1.1单例模式创建该类实例
* 1.2由Retrofit负责请求方与响应方的联接
* 1.2.1请求方由OKHttpClient负责完成
* 1.2.2响应方由RxJava对响应数据进行处理
* 1.2.2.1响应数据转换为实体数据交由Gson处理
*
* @date 2021-5-4 11:28
* @since appVer
*/
class APIClient{
/**
* 单例
*/
private object Holder{
val INSTANCE = APIClient()
}
/**
* 派生
*/
companion object{
val instance = Holder.INSTANCE;
}
/**
* 1.创建客户端API接口
* (1)WanAndroidAPI实例化
* (2)XXXAPI实例化
* (3)动态的实例化,可以使用到泛型
* (4)fun <T> instanceRetrofit(apiInterface: Class<T>): T表示此为泛型方法
* (5)apiInterface: Class<T>:表示此为泛型参数
* (6): T表示返回类型为泛型
*/
fun <T> instanceRetrofit(apiInterface: Class<T>) : T{
//1.1.1OKHttpClient请求服务器
val okHttpclient = OkHttpClient().newBuilder()
//1.1.1.1添加读取超时时间
.readTimeout(10000, TimeUnit.SECONDS)
//1.1.1.2添加连接超时时间
.connectTimeout(10000,TimeUnit.SECONDS)
//1.1.1.3添加写出超时时间
.writeTimeout(10000,TimeUnit.SECONDS)
.build()
val retrofit:Retrofit = Retrofit.Builder()
//1.1请求方 <-
.client(okHttpclient)
//1.2响应方 ->
//1.2.1RxJava来处理
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
//1.2.2Gson来解析JavaBean
.addConverterFactory(GsonConverterFactory.create())
.build()
//1.3将请求方与响应方建好后,将请求api的参数
return retrofit.create(apiInterface)
}
}
4.自定义操作符拦截包装类
import android.content.Context
import com.gdc.kotlinproject.entity.LoginResponseWrapper
import com.gdc.kotlinproject.views.LoadingDialog
import io.reactivex.Observer
import io.reactivex.disposables.Disposable
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.kotlinproject.net
* @file
* @Description:
* 1.RxJava自定义操作符
* 1.1目的是将包装bean拆成两份
* (1)如果成功,将data给UI
* (2)如果失败,将错误信息msg给UI
* 1.2操作符
* (1)在起点到终点的流向过程当中,该操作符成为了观察者
* (2)流向的类型是包装bean,因此泛型类型是包装bean
* (3)不想将包装bean泛型的具体参数类型限定死,即LoginResponse,因此包装beanLoginResponseWrapper<T>
* 定义为泛型,并且将该类定义为泛型类,是为了让用户可以动态传递.
* (4)为什么要定义为抽象类?
* 是为了抽像成功操作与失败操作
* 1.3用户自定义是否弹出加载框,需要上下文val context : Context
* @date 2021-5-5 09:46
* @since appVer
*/
abstract class APIResponse<T>(val context : Context) :Observer<LoginResponseWrapper<T>>{
/**
* 1.控制加载框是否弹出
* (1)默认弹出
*/
private var isShow : Boolean = true
/**
* 1.次构造
* (1)让对话框的显示与隐藏可控
*/
constructor(context : Context,isShow :Boolean = false) : this(context){
this.isShow = isShow;
}
/**
* 1.统一处理数据返回成功的操作
* 1.1? 允许返回数据为空
* 1.2 成功将data交给UI展示
*/
abstract fun success(data : T ?)
/**
* 1.统一处理数据响应失败的操作
* 1.1失败将错误消息丢给UI
* 1.2?表示错误消息允许为null
*/
abstract fun failure(errorMsg : String ?)
/**
* 1.弹出加载框
* (1)在起点分发的时候触发
*/
override fun onSubscribe(d: Disposable) {
if(isShow){
LoadingDialog.show(context)
}
}
/**
* 1.接收从上游流下来的数据
* (1)成功与失败的判断,根据数据data是否为null进行判断
* (2)成功调用success将data传给UI显示
*/
override fun onNext(t: LoginResponseWrapper<T>) {
//失败
if(null == t.data){
failure("登录失败,请检查原因:${t.errorMsg}")
}else{
success(t.data)
}
}
/**
* 1.处理上游流下来的错误
* (1)取消加载框的显示
*/
override fun onError(e: Throwable) {
LoadingDialog.cancel()
failure(e.message)
}
/**
* 1.停止
* (1)取消加载框
*/
override fun onComplete() {
LoadingDialog.cancel()
}
}
5.界面调用
/**
* 1.登录界面
*/
class LoginActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
user_login_bt.setOnClickListener(onClickListener)
}
/**
* 1.kotlin与java的无缝交互
* 1.1view.id不需要写view.getId()或view.setId()是因为Kotlin中自动判断调用哪个方法
* 1.1.1id的值由内部根据"="知道你是调用get还是set方法
* 1.1.2WanAndroidAPI::class.java 对应 WanAndroidAPI.class
* 1.1.3val api = APIClient.instance.instanceRetrofit(WanAndroidAPI::class.java)
*/
private val onClickListener = View.OnClickListener { view ->
when (view.id) {
//1.登录
R.id.user_login_bt -> {
val userName = user_phone_et.text.toString()
val userPwd = user_password_et.text.toString()
Log.d(Flag.TAG, "userName:$userName,userPwd:$userPwd")
APIClient.instance.instanceRetrofit(WanAndroidAPI::class.java)
//1.1全部都是RxJava知识了
//1.1.1创建被观察者,经过此步骤会返回一个Observable对象,它是RxJava的起点
//1.1.2将LoginResponseWrapper丢给RxJava慢慢的往传递,直到传给UI界面控件
.loginAction(userName, userPwd)
//1.1.3因为请求与响应是耗时操作,所以将其放到异步线程中执行。
.subscribeOn(Schedulers.io())
//1.1.4将下面更新UI的操作,分配到main线程中执行
.observeOn(AndroidSchedulers.mainThread())
/**
* (1)通过RxJava起点把包装bean中的数据,放到流中流向终点,去更新UI
* (2)以下代码拿到的是包装bean,需要对其拆卸
* (3)自定义操作符把包装bean进行拦截,把包装bean进行拆卸,如果成功,将
* 包装bean中的data丢给页面,如果失败将错误码丢给UI
*/
/*.subscribe(object : Consumer<LoginResponseWrapper<LoginResponse>> {
override fun accept(t: LoginResponseWrapper<LoginResponse>) {
}
})*/
.subscribe(object : APIResponse<LoginResponse>(this) {
override fun success(data: LoginResponse?) {
Log.i(Flag.TAG, "success:$data")
Toast.makeText(this@LoginActivity, "登录成功", Toast.LENGTH_SHORT).show()
}
override fun failure(errorMsg: String?) {
Log.i(Flag.TAG, "success:$errorMsg")
Toast.makeText(this@LoginActivity, "登录失败", Toast.LENGTH_SHORT).show()
}
})
}
}
}
}
6.java与Kotlin互调
(1)Kotlin会比Java的编译速度更慢,因为它生成的内容较多。
6.1Java调用Kotlin静态类的静态方法
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.lib.kt
* @file
* @Description:
* 1.工具类
* (1)演示java与Kotlin互调
* (2)此类会被生成为一个public final class UtilsKt类
* (3)在此类中生成的方法都为static final的方法
* public static final void show()
*
*
* @date 2021-5-8 09:06
* @since appVer
*/
fun show(info : String){
println(info)
}
6.2Java调用Kotlin普通类的方法
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.lib.kt
* @file
* @Description:
* 1.演示Java与Kotlin互调
* (1)有具体的类名,生成的类public final class MyUtils
* @date 2021-5-8 09:18
* @since appVer
*/
class MyUtils {
fun show(info : String){
println(info)
}
}
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.lib.java
* @file
* @Description:
* 1.Java与Kotlin互调
* (1)Java调用Kotlin静态类的静态方法
* (2)Java调用Kotlin普通类的方法
* @date 2021-5-8 09:08
* @since appVer
*/
public class Client {
public static void main(String[] args) {
UtilsKt.show("你好!");
new MyUtils().show("中华人民共和国");
}
}
6.3Kotlin调用java
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.lib.kt
* @file
* @Description:
* 1.演示Kotlin调用java
* 1.1调用java常量
* (1)in是kotlin的区间,此处与Java的常量冲突,因此使用''解决冲突问题
* 1.2调用java函数
* (1)有一个String!代表不确定性,即不知道什么时候有值,什么时候没值
* (2)最好使用变量接收
* (3)Student().string.length:写法错误,有可能引发空指针异常
* 1.3class传递
*
* @date 2021-5-8 09:29
* @since appVer
*/
fun main() {
//(1)调用java常量
println(Student.`in`)
/**
* (2)调用java函数
*/
//Student().string.length
var str : String ? = Student().string
println(str?.length)
//(3)传递java类给kotlin方法
showClass1(Student::class.java)
//(4)传递kotlin类给kotlin方法
showClass2(KtStudent::class)
}
/**
* 1.形参里面全部是java类
*/
fun showClass1(clazz:Class<Student>){
}
/**
* 1.形参里面全部是Kotlin类
*/
fun showClass2(clazz: KClass<KtStudent>){
}
(1)java类
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.lib.java
* @file
* @Description:
* 1.演示Kotlin调用Java类
* @date 2021-5-8 09:23
* @since appVer
*/
public class Student {
public static String in = "中国人民解放军";
public String getString(){
return null;
}
}
(2)Kotlin类
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.lib.kt
* @file
* @Description:
* @date 2021-5-8 09:46
* @since appVer
*/
class KtStudent{
}
6.4Kotlin使用Java接口回调
(1)java接口
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.lib.java
* @file
* @Description:
* 1.java接口
* @date 2021-5-8 10:00
* @since appVer
*/
public interface JavaCallback {
void show(String info);
}
(2)java接口管理者
public class JavaManager {
public void setCallBack(JavaCallback javaCallback){
javaCallback.show("中华人民共和国");
}
}
(3)Kotlin使用Java接口回调
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.lib.kt
* @file
* @Description:
* 1.Kotlin使用Java接口回调
* @date 2021-5-8 10:02
* @since appVer
*/
fun main(){
//1.第一种写法
JavaManager().setCallBack({
println(it)
})
//2.第二种写法
JavaManager().setCallBack(object : JavaCallback{
override fun show(info: String?) {
println(info)
}
})
//3.第三种写法
JavaManager().setCallBack {
info -> println(info)
}
//4.第4种写法
val callback = JavaCallback {
println(it)
}
JavaManager().setCallBack(callback)
//5.第5种写法
val callback2 = object : JavaCallback{
override fun show(info: String?) {
println(info)
}
}
JavaManager().setCallBack(callback2)
}
6.5Kotlin中使用kotlin接口回调
(1)kotlin接口
interface KTCallback {
fun show(name : String)
}
(2)回调管理
class KtManager{
fun setCallback(callback : KTCallback){
callback.show("中华人民共和国")
}
}
fun main(){
//1.第一种写法
KtManager().setCallback(object :KTCallback{
override fun show(name: String) {
}
})
//2.第二种写法
val c = object : KTCallback{
override fun show(name: String) {
}
}
KtManager().setCallback(c)
/**
* 1.Kotlin不能向Java一样如此使用回调
*/
/*KtManager().setCallback(KTCallback {
})*/
}
fun main(){
/**
* 1.kotlin使用java的回调
*/
Handler(Looper.getMainLooper(),object : Handler.Callback{
override fun handleMessage(msg: Message): Boolean {
return true
}
})
/**
* 2.Kotlin的lamboda表达式
*/
Handler(Looper.getMainLooper(),Handler.Callback {
true
})
/**
* 3.使用线程
*/
Thread{
Log.e("","main:")
}.start()
}
7.打赏鼓励
感谢您的细心阅读,您的鼓励是我写作的不竭动力!!!
7.1微信打赏
7.2支付宝打赏
以上是关于02Kotlin项目实操之Retrofit网络模型的主要内容,如果未能解决你的问题,请参考以下文章