快速打造Kotlin+MVP+Rxjava+Retrofit项目架构(引用Google推荐架构模式:契约接口)
文件目录:
主要代码示例:
- 1、一个登录模型(也叫bean、entity)
/**
* 后台规定的接口命名的字段是大写开头
*/
class LoginModel : Base() {
/**
* Ext : {"Authority":3,"Token":"213bfc688a7e099b1f2a27b64f59c9e1"}
* Message : 登录成功
* State : true
*/
var ext: ExtBean? = null
class ExtBean {
/**
* Authority : 3
* Token : 213bfc688a7e099b1f2a27b64f59c9e1
*/
var authority: Int = 0
var token: String? = null
}
}
- 2、一个登录的契约接口
interface View : BaseContract.BaseView {
fun loginSus(loginModel: LoginModel) //登录成功
fun err(code: Int, message: String) //出错
}
interface Presenter : BaseContract.BasePresenter {
fun login(telephoneNumber: String, verificationCode: String, token: String) //登录
}
顺便贴出BaseContract契约接口基类
/**
* 对应mvp中的contract契约接口
*/
interface BaseContract {
interface BasePresenter {
/*该方法可以获取到View实例对象*/
fun attachView(view: T)
/*释放View对象的引用,gc才能回收View*/
fun detachView()
}
interface BaseView {
//view的一些共有方法
fun showError(e: Throwable)
fun complete()
}
}
- 3、一个实现了View接口充当V层的Activity
/**
* 模拟登录的view层
*/
class MainActivity : BaseActivity(),LoginContract.View {
override fun err(code: Int, message: String) {
ToastUtils.showShort("错误码:$code\n错误信息:$message")
}
override fun loginSus(loginModel: LoginModel) {
disMissLoading()
if (loginModel.State) {
ToastUtils.showShort("登录成功")
}else{
ToastUtils.showShort(loginModel.Message)
}
}
override fun showError(e: Throwable) {
disMissLoading()
}
override fun complete() {
}
override fun getLayoutId(): Int = R.layout.activity_main
override fun configView() {
login.setOnClickListener({
showLoading()
mPresenter!!.login("18381309101","1111","") })
}
override fun initData() {
}
override fun initPresenter(): LoginContract.Presenter = LoginPresenter()
}
- 实现Presenter,充当P层的一个登录的Presenter
class LoginPresenter : RxPresenter(), LoginContract.Presenter {
/**
* 登录
* @param telephoneNumber
* @param verificationCode
* @param token
*/
override fun login(telephoneNumber: String, verificationCode: String, token: String) {
val subscription = HttpManager.getWorkHttpService()!!.signIn(telephoneNumber, verificationCode, token)
.compose(ScheduleTransformer.instance)
.subscribe(object : ObserverImp() {
override fun onErr(errCode: Int, str: String) {
mView!!.err(errCode,str)
}
override fun doNext(loginModel: Any) {
mView!!.loginSus(loginModel as LoginModel)
}
})
addSubscribe(subscription)
}
}
到这里mvp构建就已经完成了,但是那些日常操作:统一错误处理、文件进度监听、Retorfit的自定义拦截器、内存泄漏处理、Retrofit自定义转换器等等还需要完成。。。
一些重要的代码:
- 统一错误处理
override fun onError(e: Throwable) {
var e = e
var throwable = e
//获取最根源的异常
while (throwable.cause != null) {
if (e is HttpException) {
break
}
e = throwable
throwable = throwable.cause!!
}
if (e is HttpException) {
when (e.code()) {
UNAUTHORIZED -> onErr(UNAUTHORIZED, "")
FORBIDDEN -> onErr(FORBIDDEN, "权限错误") //权限错误,需要实现
NOT_FOUND -> onErr(NOT_FOUND, "")
REQUEST_TIMEOUT -> onErr(REQUEST_TIMEOUT, "")
GATEWAY_TIMEOUT -> onErr(GATEWAY_TIMEOUT, "")
INTERNAL_SERVER_ERROR -> onErr(INTERNAL_SERVER_ERROR, "")
BAD_GATEWAY -> onErr(BAD_GATEWAY, "")
SERVICE_UNAVAILABLE -> onErr(SERVICE_UNAVAILABLE, "")
else -> onErr(ERR_CODE_NET, "")
}
} else if (e is SocketTimeoutException) {
onErr(GATEWAY_TIMEOUT, "请求超时!")
} else if (e is UnknownHostException) {
onErr(ERR_CODE_NET, "网络连接失败!")
} else {
onErr(ERR_CODE_UNKNOWN, "未知错误!")
}
}
- 2、文件进度监听
override fun read(sink: Buffer, byteCount: Long): Long {
try {
val bytesRead = super.read(sink, byteCount)
if (totalBytesRead == 0L && listener != null) {
listener.DLoadStart()
}
totalBytesRead += if (bytesRead != -1L) bytesRead else 0
if (null != listener) {
if (bytesRead == -1L) {
listener.DLoadSuccess()
}
if ((totalBytesRead * 100L / responseBody.contentLength()).toInt() > lastPro) {
listener.DLoadProgress((totalBytesRead * 100L / responseBody.contentLength()).toInt())
}
lastPro = (totalBytesRead * 100L / responseBody.contentLength()).toInt()
}
return bytesRead
} catch (e: IOException) {
listener?.DLoadFail()
}
return 0L
}
- 3、自定义文件下载拦截器
/**
* 文件下载拦截器
*/
class DownLoadInterceptor(private val listener: DLProListener) : Interceptor {
@Throws(IOException::class)
override fun intercept(chain: Interceptor.Chain): Response {
val originalResponse = chain.proceed(chain.request())
return originalResponse.newBuilder()
.body(FileResBody(originalResponse.body(), listener))
.build()
}
}
- 4、内存泄漏处理,释放对activity 的引用
override fun attachView(view: T) {
this.mView = view
}
override fun detachView() {
this.mView = null
unSubscribe()
}
- 5、自定义单例的Retrofit转换器
/**
* 单例实现的转换器,统一指定每一个接口请求实在io线程,回调在ui线程
*/
class ScheduleTransformer
/**
* 私有的构造函数
*/
private constructor() : Observable.Transformer {
/**
*懒加载内部单例
*/
private object TransformerHolder {
private val instance: ScheduleTransformer? = null
fun getInstance(): ScheduleTransformer {
return instance ?: ScheduleTransformer()
}
}
override fun call(tObservable: Observable): Observable {
return tObservable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
/**
* 伴生
*/
companion object {
val instance: ScheduleTransformer
get() = TransformerHolder.getInstance()
}
}
该架构用起来十分方便和灵活,里面还有常用的一些基类和处理类,已经在正式项目中使用,请大胆尝试,Github地址:实战MVP架构,包含JAVA版本,欢迎打星鼓励!