04Kotlin登录功能MVP基类封装
Posted 清风百草
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了04Kotlin登录功能MVP基类封装相关的知识,希望对你有一定的参考价值。
(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)好好活就是做有意义的事情.
(8)亡羊补牢,为时未晚
(9)科技领域,没有捷径与投机取巧。
(10)有实力,一年365天都是应聘的旺季,没实力,天天都是应聘的淡季。
(11)基础不牢,地动天摇
(12)写博客初心:成长自己,辅助他人。当某一天离开人世,希望博客中的思想还能帮人指引方向.
(13)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~
Kotlin登录功能MVP基类封装
Kotlin体系文档
文章目录
1.架构图示
红框部分为基类的基类
2.BaseActivity基类
2.1知识点
2.1.1泛型的使用
2.1.2继承与接口实现
package com.gdc.kotlinproject.base
import android.os.Bundle
import androidx.appcompat.app.ActionBar
import androidx.appcompat.app.AppCompatActivity
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.kotlinproject.base
* @file
* @Description:
* 1.是所有Activity的父类
*
* 1.1继承AppCompatActivity类
*
* 1.2为了确保该类被其他类继承,成员变量或函数被继承,因此将其声明为abstract类
*
* 1.3具体使用哪个Presenter类不需要关心,所以使用泛型来标示
*
* 1.4限定泛型必须是LoginPresenter子类才可以
*
* (1)P : LoginPresenter类似于java中P extends LoginPresenter
* (2)P extends LoginPresenter & Serializable 类似于where P : IBasePresenter,P:Serializable,需要单独做限定
*
* 1.5不实例化presenter,面向于抽象,不面向细节编程,因此定义抽象方法,createP(),让其在子类中实现,返回类型为泛型
*
* 1.6强制子类在onDestroy执行时调用recycle()函数
*
* 1.7工具类函数(公用的函数)
*
*/
abstract class BaseActivity<P> : AppCompatActivity() where P : IBasePresenter
lateinit var presenter: P
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
presenter = createP()
/**
* 1.还可以自己扩展很多公用功能
*/
//setContentView(getLayoutID())
//initView()
//initData()
abstract fun createP() : P
abstract fun recycle()
override fun onDestroy()
super.onDestroy()
recycle()
/**
* 1.类似于工具类函数
* 1.1暴露给子类直接调用,完成隐藏ActionBar的功能
* 1.2任何Java代码的东西,必须用?允许其为空
*/
fun hideActionBar()
val actionBar : ActionBar? = supportActionBar
actionBar?.hide()
3.IBasePresenter接口
/**
* @author XiongJie
* @version appVer
* @Package com.gdc.kotlinproject.base
* @file
* @Description:
* 1.所有P层的最上层父类
* 2.即在接口之上再实现接口
* 3.也就是所有接口必须要实现的方法写在此接口中
* @date 2021-5-13 10:41
* @since appVer
*/
interface IBasePresenter
//fun attachView()
//1.试图离开了(Activity/Fragmet离开了)消毁释放资源
fun unAttachView()
3.View层
import android.content.Intent
import android.os.Bundle
import android.util.Log
import android.view.View
import android.widget.Toast
import com.gdc.kotlinproject.R
import com.gdc.kotlinproject.base.BaseActivity
import com.gdc.kotlinproject.config.Flag
import com.gdc.kotlinproject.entity.LoginRegisterResponse
import com.gdc.kotlinproject.modules.login.interfaces.LoginPresenter
import com.gdc.kotlinproject.modules.login.interfaces.LoginView
import com.gdc.kotlinproject.modules.register.RegisterActivity
import kotlinx.android.synthetic.main.activity_login.*
/**
* 1.登录界面
* (1)View层的实现,即LoginView接口的实现,只需要关注P层,实现Presenter层
* (2)Presenter层的创建在BaseActivity中定义,在具体Activity子类中实现
* 2.MVP优势
* (1)MVP模式中,Activity与Fragment只做View显示角色,不做Controller与Model相关工作
* (2)单独可以拆卸便于测试
* 3.设计模式的选择
* (1)只有合适与不合适,没有好与不好。
* (2)MVC可以减少创建多个类,但是一个类业务复杂情况下会有上万行代码情况出现,不利于项目维护。
* (3)MVP可以需要创建多个类完成业务,但是职责清晰,便于测试,便于团队开发大型项目。
*/
class LoginActivity : BaseActivity<LoginPresenter>() ,LoginView
override fun onCreate(savedInstanceState: Bundle?)
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
user_login_bt.setOnClickListener(onClickListener)
user_register_tv.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")
//1.1调用Presenter层实现业务
presenter.loginAction(this@LoginActivity,userName,userPwd)
R.id.user_register_tv ->
val intent = Intent(this@LoginActivity,RegisterActivity::class.java);
startActivity(intent)
/**
* 响应
*/
override fun loginSucess(loginRegisterBean: LoginRegisterResponse?)
Toast.makeText(this@LoginActivity, "登录成功", Toast.LENGTH_SHORT).show()
override fun loginFailure(errorMsg: String?)
Toast.makeText(this@LoginActivity, "登录失败", Toast.LENGTH_SHORT).show()
/**
* 子类中实现创建Presenter对象
*/
override fun createP(): LoginPresenter = LoginPresenterImpl(this)
override fun recycle()
presenter.unAttachView()
4.Presenter层
interface LoginPresenter :IBasePresenter
/**
* 1.登录
* (1)context是为了给网络模型用的
*/
fun loginAction(context : Context,username:String,password : String)
/**
* 1.监听Module层的接口回调
*/
interface OnLoginListener
fun loginSucess(loginRegisterBean: LoginRegisterResponse?)
fun loginFailure(errorMsg : String ?)
5.Module层
interface LoginModule
/**
* 1.取消请求动作
*/
fun cancelRequest()
/**
* 1.登录
* (1)接口回调:把data结果,给Presenter层
*/
fun login(
context : Context,
username : String,
password:String,
onLoginListener:LoginPresenter.OnLoginListener
)
class LoginModelImpl :LoginModule
override fun cancelRequest()
override fun login(
context: Context,
username: String,
password: String,
onLoginListener: LoginPresenter.OnLoginListener)
APIClient.instance.instanceRetrofit(WanAndroidAPI::class.java)
//1.1全部都是RxJava知识了
//1.1.1创建被观察者,经过此步骤会返回一个Observable对象,它是RxJava的起点
//1.1.2将LoginResponseWrapper丢给RxJava慢慢的往传递,直到传给UI界面控件
.loginAction(username, password)
//1.1.3因为请求与响应是耗时操作,所以将其放到异步线程中执行。
.subscribeOn(Schedulers.io())
//1.1.4将下面更新UI的操作,分配到main线程中执行
.observeOn(AndroidSchedulers.mainThread())
.subscribe(object : APIResponse<LoginRegisterResponse>(context)
override fun success(data: LoginRegisterResponse?)
Log.i(Flag.TAG, "success:$data")
//1.成功
onLoginListener.loginSucess(data)
override fun failure(errorMsg: String?)
Log.i(Flag.TAG, "success:$errorMsg")
//2.失败
onLoginListener.loginFailure(errorMsg)
)
6.网络层
6.1网络请求客户端
(1)Retrofit负责请求方与响应方的联接
(2)请求方由OKHttpClient负责完成
(3)RxJava负责响应数据处理
(3)Gson负责将响应数据转换为实体数据
/**
* @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请求方 <-
.baseUrl(Flag.BASE_URL)
.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)
6.2客户端请求接口API
/**
* @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<LoginRegisterResponseWrapper<LoginRegisterResponse>>
/**
* 注册API
*/
@POST("/user/register")
@FormUrlEncoded
fun registerAction(@Field("username") username: String,
@Field("password") password: String,
@Field("password") repassword: String)
: Observable<LoginRegisterResponseWrapper<LoginRegisterResponse>>
6.3自定义操作符处理业务响应数据
/**
* @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<LoginRegisterResponseWrapper<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: LoginRegisterResponseWrapper<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()
7.打赏鼓励
感谢您的细心阅读,您的鼓励是我写作的不竭动力!!!
7.1微信打赏
7.2支付宝打赏
以上是关于04Kotlin登录功能MVP基类封装的主要内容,如果未能解决你的问题,请参考以下文章
Android MVP-编程思想3(MVP-内存泄露问题处理,基类封装,有没有必要再使用软引用?)
Android当中的MVP模式View 层 Activity 的基类--- BaseMvpActivity 的封装