目录
1.2、模型层(处理网络请求获取到数据类 对应MainActivityModel,请求封装在 RetrofitUtils中)
1.3、视图层(Activity作为界面展示,接口 MainActivityView 回调界面更新)
1.4、主持层/处理层(MainPresenter 作为主持者,接口是父类 IMainActivityPresenter)
2.2、ViewModel层(QueryWeatherViewModel =>Model层这里只是简单的JavaBean,可以抽出一个接口Model来网络请求的)
2.3、视图层(这里的视图层主要是DataBinding的Layout和Activity)
Android的架构模式的学习和使用(MVP/MVVM)
通用的核心库:
//引入rxjava
implementation 'io.reactivex.rxjava2:rxjava:2.0.1'
implementation 'io.reactivex.rxjava2:rxandroid:2.0.1'
//引入Retrofit
implementation 'com.squareup.retrofit2:retrofit:2.6.2'
implementation 'com.squareup.okhttp3:logging-interceptor:3.14.4'
implementation 'com.squareup.retrofit2:converter-gson:2.6.2'
implementation 'com.squareup.retrofit2:adapter-rxjava2:2.6.2'
一、MVP模式(Kotlin编写)
1.1、例子项目目录展示:
1.2、模型层(处理网络请求获取到数据类 对应MainActivityModel,请求封装在 RetrofitUtils中)
package com.zbv.mvp_android.`interface`.main
import com.zbv.mvp_android.javabean.BannarBean
import com.zbv.mvp_android.javabean.HomeDataFirstBean
import com.zbv.mvp_android.net.ResponseBean
import com.zbv.mvp_android.net.RetrofitUtils
import io.reactivex.Observable
/**
* author: qzx
* Date: 2019/11/21 8:58
*/
class MainActivityModel {
fun getBananarData(): Observable<ResponseBean<MutableList<BannarBean>>> {
return RetrofitUtils.getInstance().getRequest()!!.getBannarDatas()
}
fun getHomeData(pageIndex: Int): Observable<ResponseBean<HomeDataFirstBean>> {
return RetrofitUtils.getInstance().getRequest()!!.getHomeDatas(pageIndex)
}
}
1.3、视图层(Activity作为界面展示,接口 MainActivityView 回调界面更新)
package com.zbv.mvp_android.`interface`.main
import com.zbv.mvp_android.javabean.BannarBean
import com.zbv.mvp_android.javabean.HomeDataSecondBean
/**
* author: qzx
* Date: 2019/11/21 8:49
*/
interface MainActivityView {
fun getBananarSuccess(bananarData: MutableList<BannarBean>)
fun getBananarFail(errorMsg: String)
fun getHomeDataSuccess(homeData: MutableList<HomeDataSecondBean>)
fun getHomeDataFail(errorMsg: String)
}
package com.zbv.mvp_android
import android.graphics.Rect
import android.os.Bundle
import android.support.v7.app.AppCompatActivity
import android.support.v7.widget.LinearLayoutManager
import android.support.v7.widget.RecyclerView
import android.util.Log
import android.widget.Toast
import com.zbv.mvp_android.`interface`.main.IMainActivityPresenter
import com.zbv.mvp_android.`interface`.main.MainActivityView
import com.zbv.mvp_android.`interface`.main.MainPresenter
import com.zbv.mvp_android.adapter.HomeRVAdapter
import com.zbv.mvp_android.adapter.OriginalRVHomeAdapter
import com.zbv.mvp_android.bannar.GlideImageLoader
import com.zbv.mvp_android.javabean.BannarBean
import com.zbv.mvp_android.javabean.HomeDataSecondBean
import kotlinx.android.synthetic.main.activity_main.*
/**
* Android MVC 模式中 Activity做为Controller层,也作为View层
* 这里采用 MVP 模式 Activity作为View层,持有Presenter对象,在Presenter主持层中处理逻辑,完全隔离Model层,采用接口方式最好
* todo presenter view model都有一个接口父类这样耦合会更低点
* */
class MainActivity : AppCompatActivity(), MainActivityView {
private val presenter: IMainActivityPresenter by lazy {
MainPresenter(this)
}
override fun getBananarSuccess(bananarData: MutableList<BannarBean>) {
imageUrls = bananarData
var urls: MutableList<String> = mutableListOf()
for (image in imageUrls!!) {
urls.add(image.imagePath!!)
}
banner.setImages(urls)
banner.start()
}
override fun getBananarFail(errorMsg: String) {
Log.e("zbv", "获取滚动Bananar失败... $errorMsg")
Toast.makeText(this, "获取滚动Bananar失败... $errorMsg", Toast.LENGTH_SHORT).show()
}
override fun getHomeDataSuccess(homeData: MutableList<HomeDataSecondBean>) {
Log.e("zbv", "home data success..." + homeData)
items.clear()
for (item in homeData) {
items.add(item)
}
adapter?.notifyDataSetChanged()
myAdapter?.notifyDataSetChanged()
}
override fun getHomeDataFail(errorMsg: String) {
Log.e("zbv", "获取HomeData失败... $errorMsg")
Toast.makeText(this, "获取HomeData失败... $errorMsg", Toast.LENGTH_SHORT).show()
}
var imageUrls: MutableList<BannarBean>? = null
var items: MutableList<HomeDataSecondBean> = mutableListOf()
var adapter: HomeRVAdapter? = null
var myAdapter: OriginalRVHomeAdapter? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
presenter.getBananarData()
presenter.getHomeData(200)
// -----------------------轮播------------------------
banner.setImageLoader(GlideImageLoader())
// -----------------------轮播------------------------
//-----------------------RecyclerView---------------
recyclerview.layoutManager = LinearLayoutManager(this)
recyclerview.addItemDecoration(object : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, itemPosition: Int, parent: RecyclerView) {
super.getItemOffsets(outRect, itemPosition, parent)
outRect.set(0, 7, 0, 7)
}
})
myAdapter = OriginalRVHomeAdapter(this, items)
adapter = HomeRVAdapter(R.layout.rv_item_layout, items)
recyclerview.adapter = myAdapter
//-----------------------RecyclerView---------------
}
override fun onDestroy() {
super.onDestroy()
presenter.unsubscribe()
}
}
1.4、主持层/处理层(MainPresenter 作为主持者,接口是父类 IMainActivityPresenter)
package com.zbv.mvp_android.`interface`.main
import com.zbv.mvp_android.javabean.BannarBean
import com.zbv.mvp_android.javabean.HomeDataFirstBean
import com.zbv.mvp_android.net.ResponseBean
import io.reactivex.ObservableTransformer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.Function
import io.reactivex.schedulers.Schedulers
/**
* author: qzx
* Date: 2019/11/21 8:56
*
* 和模型层一样的两个方法
*/
class MainPresenter(view: MainActivityView) : IMainActivityPresenter {
private var view: MainActivityView? = null
init {
this.view = view
}
private val model: MainActivityModel by lazy {
MainActivityModel()
}
private val disposable: CompositeDisposable by lazy {
CompositeDisposable()
}
/**
* 切换线程操作
*/
fun <T> applySchedulers(): ObservableTransformer<T, T> {
return ObservableTransformer { observable -> observable.observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()) }
}
/**
* 获取首页条幅栏
* */
override fun getBananarData() {
var bananarCompose = model?.getBananarData()?.compose(applySchedulers())
.map(object : Function<ResponseBean<MutableList<BannarBean>>, MutableList<BannarBean>> {
override fun apply(t: ResponseBean<MutableList<BannarBean>>?): MutableList<BannarBean> {
return t?.data!!
}
})
.subscribe({ t ->
view?.getBananarSuccess(t)
}, { throwable ->
view?.getBananarFail(throwable.message!!)
})
disposable.add(bananarCompose)
}
/**
* 获取首页数据
* */
override fun getHomeData(pageIndex: Int) {
var homeCompose = model?.getHomeData(pageIndex)?.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
.map(object : Function<ResponseBean<HomeDataFirstBean>, HomeDataFirstBean> {
override fun apply(t: ResponseBean<HomeDataFirstBean>?): HomeDataFirstBean {
return t?.data!!
}
})
.subscribe({ t ->
view?.getHomeDataSuccess(t.datas!!)
}, { throwable ->
view?.getHomeDataFail(throwable.message!!)
})
disposable.add(homeCompose)
}
/**
* 取消订阅
* */
override fun unsubscribe() {
disposable.dispose()
}
}
package com.zbv.mvp_android.`interface`.main
/**
* author: qzx
* Date: 2019/11/22 13:42
*/
interface IMainActivityPresenter {
fun unsubscribe()
fun getBananarData()
fun getHomeData(pageIndex: Int)
}
二、MVVM模式(Kotlin编写)
2.1、例子项目目录展示:
2.2、ViewModel层(QueryWeatherViewModel =>Model层这里只是简单的JavaBean,可以抽出一个接口Model来网络请求的)
package com.zbv.androidmvvm.viewmodel
import android.databinding.ObservableBoolean
import android.databinding.ObservableField
import android.util.Log
import com.zbv.androidmvvm.model.WeatherData
import com.zbv.androidmvvm.model.WeatherInfo
import com.zbv.androidmvvm.net.RetrofitUtil
import com.zbv.androidmvvm.net.WeatherRequest
import io.reactivex.ObservableTransformer
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.functions.Function
import io.reactivex.schedulers.Schedulers
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
/**
* author: qzx
* Date: 2019/11/22 9:07
*/
class QueryWeatherViewModel {
val loading: ObservableBoolean = ObservableBoolean(false)
val loadingSuccess: ObservableBoolean = ObservableBoolean(false)
val loadingFailure: ObservableBoolean = ObservableBoolean(false)
val city: ObservableField<String> = ObservableField()
val cityId: ObservableField<String> = ObservableField()
val temp1: ObservableField<String> = ObservableField()
val temp2: ObservableField<String> = ObservableField()
val weather: ObservableField<String> = ObservableField()
val time: ObservableField<String> = ObservableField()
private var call: Call<WeatherData>? = null
//rxjava 管理生命周期
private val disposable: CompositeDisposable by lazy {
CompositeDisposable()
}
fun queryWeather() {
loading.set(true)
loadingSuccess.set(false)
loadingFailure.set(false)
// //方式一
// call = RetrofitUtil.getInstance().retrofit?.create(WeatherRequest::class.java)?.queryWeather()
// //方式二
// call = RetrofitUtil.getInstance().getRequest(WeatherRequest::class.java)?.queryWeather()
//
// call?.enqueue(object : Callback<WeatherData> {
// override fun onFailure(call: Call<WeatherData>, t: Throwable) {
// if (call.isCanceled) {
// Log.e("zbv", "user canceled request")
// } else {
// loading.set(false)
// loadingFailure.set(true)
// }
// }
//
// override fun onResponse(call: Call<WeatherData>, response: Response<WeatherData>) {
// val weatherInfo: WeatherInfo? = response.body()?.weatherinfo
//
// city.set(weatherInfo?.city)
// cityId.set(weatherInfo?.cityid)
// temp1.set(weatherInfo?.temp1)
// temp2.set(weatherInfo?.temp2)
// weather.set(weatherInfo?.weather)
// time.set(weatherInfo?.ptime)
//
// loading.set(false)
// loadingSuccess.set(true)
// }
// })
//方式三 rxjava
var compose = RetrofitUtil.getInstance().getRequest(WeatherRequest::class.java)?.queryWeather2()
?.compose(applySchedulers())
?.map(object : Function<WeatherData, WeatherInfo> {
override fun apply(t: WeatherData?): WeatherInfo? {
return t?.weatherinfo
}
})
?.subscribe({ t ->
city.set(t.city)
cityId.set(t.cityid)
temp1.set(t.temp1)
temp2.set(t.temp2)
weather.set(t.weather)
time.set(t.ptime)
loading.set(false)
loadingSuccess.set(true)
}, { throwable ->
loading.set(false)
loadingFailure.set(true)
})
disposable.add(compose)
}
/**
* 取消请求,或者在生命周期结束时调用,结束进行中的请求操作等
* */
fun cancelRequest() {
call?.cancel()
if (!disposable.isDisposed) {
disposable.dispose()
}
}
/**
* 切换线程操作
*/
fun <T> applySchedulers(): ObservableTransformer<T, T> {
return ObservableTransformer { observable -> observable.observeOn(AndroidSchedulers.mainThread()).subscribeOn(Schedulers.io()) }
}
}
2.3、视图层(这里的视图层主要是DataBinding的Layout和Activity)
package com.zbv.androidmvvm
import android.databinding.DataBindingUtil
import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import com.zbv.androidmvvm.databinding.ActivityMainBinding
import com.zbv.androidmvvm.viewmodel.QueryWeatherViewModel
class MainActivity : AppCompatActivity() {
private var viewmodel: QueryWeatherViewModel? = null
private var mDataBinding: ActivityMainBinding? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//创建DataBinding
mDataBinding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
//创建ViewModel
viewmodel = QueryWeatherViewModel()
//绑定ViewModel
mDataBinding?.viewModel = viewmodel
}
override fun onDestroy() {
super.onDestroy()
viewmodel?.cancelRequest()
}
}
附上绑定的Layout:
<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<data>
<import type="android.view.View" />
<variable
name="viewModel"
type="com.zbv.androidmvvm.viewmodel.QueryWeatherViewModel" />
</data>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="@dimen/default_content_padding">
<Button
android:id="@+id/btn_query_weather"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:enabled="@{viewModel.loading ? false : true}"
android:onClick="@{() -> viewModel.queryWeather()}"
android:text="@string/query_weather" />
<RelativeLayout
android:id="@+id/vg_weather_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@id/btn_query_weather"
android:layout_marginTop="@dimen/query_weather_margin"
android:visibility="@{viewModel.loadingSuccess ? View.VISIBLE : View.GONE}">
<TextView
android:id="@+id/tv_city"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/city"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_city_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/tv_city"
android:layout_toRightOf="@id/tv_city"
android:text="@{viewModel.city}"
tools:text="杭州" />
<TextView
android:id="@+id/tv_city_id"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_city"
android:layout_marginTop="@dimen/query_weather_margin"
android:text="@string/city_id"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_city_id_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/tv_city_id"
android:layout_toRightOf="@id/tv_city_id"
android:text="@{viewModel.cityId}"
tools:text="101210101" />
<TextView
android:id="@+id/tv_temp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_city_id"
android:layout_marginTop="@dimen/query_weather_margin"
android:text="@string/temperature"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_temp1_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/tv_temp"
android:layout_toRightOf="@id/tv_temp"
android:text="@{viewModel.temp1}"
tools:text="5℃" />
<TextView
android:id="@+id/tv_tilde"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/tv_temp"
android:layout_toRightOf="@id/tv_temp1_value"
android:text="@string/tilde" />
<TextView
android:id="@+id/tv_temp2_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/tv_temp"
android:layout_toRightOf="@id/tv_tilde"
android:text="@{viewModel.temp2}"
tools:text="10℃" />
<TextView
android:id="@+id/tv_weather"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_temp"
android:layout_marginTop="@dimen/query_weather_margin"
android:text="@string/weather"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_weather_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/tv_weather"
android:layout_toRightOf="@id/tv_weather"
android:text="@{viewModel.weather}"
tools:text="晴" />
<TextView
android:id="@+id/tv_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/tv_weather"
android:layout_marginTop="@dimen/query_weather_margin"
android:text="@string/release_time"
android:textStyle="bold" />
<TextView
android:id="@+id/tv_time_value"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBottom="@id/tv_time"
android:layout_toRightOf="@id/tv_time"
android:text="@{viewModel.time}"
tools:text="10:00" />
</RelativeLayout>
<ProgressBar
android:id="@+id/pb_progress"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:visibility="@{viewModel.loading ? View.VISIBLE : View.GONE}" />
<TextView
android:id="@+id/tv_query_failure"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="@string/query_failure"
android:visibility="@{viewModel.loadingFailure ? View.VISIBLE : View.GONE}" />
</RelativeLayout>
</layout>
重要一点是Kotlin需要引入(app中的build.gradle):
apply plugin: 'kotlin-kapt'
三、例子项目下载(推荐百度云下载,免费)
百度云免费下载:
MVVM例子项目 链接:https://pan.baidu.com/s/1IAlfZnZNyo6JNEP7xgTZFQ 提取码:6awq
MVP例子项目 链接:https://pan.baidu.com/s/14bpT3xPCDN0dd7MeJi_wTA 提取码:g2xl