前言
Kotlin+Retrofit+RxJava+MVP封裝(一)
Kotlin+Retrofit+RxJava+MVP封裝(三)
封裝
這篇文章主要是在第一篇文章的基礎(chǔ)上的一個(gè)封裝和RecyclerView的實(shí)現(xiàn)只怎,就MVP結(jié)構(gòu)來(lái)看,我們至少會(huì)有三個(gè)基類,一個(gè)網(wǎng)絡(luò)請(qǐng)求封裝類。
BaseActivity
在BaseActivity中,我們將綁定布局厢蒜,初始化Presenter,寫入吐司,頁(yè)面跳轉(zhuǎn)痹扇,等待界面等基礎(chǔ)操作。
abstract class BaseActivity <V:BaseView,T :BasePresenter<V>>: FragmentActivity(),BaseView {
//當(dāng)前Activity渲染的視圖View
private var mContextView: View? = null
private var progressDialog: Dialog? = null
open var mPresenter:T?=null
//private var mCenterText: TextView? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// 設(shè)置activity為無(wú)標(biāo)題欄
requestWindowFeature(Window.FEATURE_NO_TITLE)
mContextView = LayoutInflater.from(this).inflate(bindLayout(), null)
setContentView(mContextView)
// 初始化ui
initView()
// 初始化數(shù)據(jù)
initData()
// 添加監(jiān)聽器
initListener()
}
//布局綁定
abstract fun bindLayout(): Int
// 初始化ui
@Suppress("UNCHECKED_CAST")
protected open fun initView() {
if(mPresenter==null){
mPresenter=createPresenter()
}
mPresenter!!.attachView(this as V)
}
// 初始化數(shù)據(jù)
protected abstract fun initData()
// 添加監(jiān)聽器
protected abstract fun initListener()
// Toast
fun showToast(text: String) {
Toast.makeText(this, text, Toast.LENGTH_SHORT).show()
}
//activity跳轉(zhuǎn)
@JvmOverloads fun openActivity(targetActivityClass: Class<*>, bundle: Bundle? = null) {
val intent = Intent(this, targetActivityClass)
if (bundle != null) {
intent.putExtras(bundle)
}
startActivity(intent)
}
fun openActivity(targetActivityClass: Class<*>, targetName: String, targetMessage: String?) {
val intent = Intent(this, targetActivityClass)
if (targetMessage != null) {
intent.putExtra(targetName, targetMessage)
}
startActivity(intent)
}
//activity跳轉(zhuǎn)并關(guān)閉當(dāng)前頁(yè)面
fun openActivityAndCloseThis(targetActivityClass: Class<*>, targetName: String, targetMessage: String) {
openActivity(targetActivityClass, targetName, targetMessage)
this.finish()
}
fun openActivityAndCloseThis(targetActivityClass: Class<*>) {
openActivity(targetActivityClass)
this.finish()
}
fun openActivityAndCloseThis(targetActivityClass: Class<*>, bundle: Bundle) {
openActivity(targetActivityClass, bundle)
this.finish()
}
//顯示等待動(dòng)畫
override fun LoadingShow() {
progressDialog = Dialog(this, R.style.progress_dialog)
progressDialog!!.setContentView(R.layout.dialog)
progressDialog!!.setCancelable(true)
progressDialog!!.window!!.setBackgroundDrawableResource(android.R.color.transparent)
progressDialog!!.setCanceledOnTouchOutside(false)
progressDialog!!.show()
}
//隱藏等待動(dòng)畫
override fun LoadingDis() {
if (progressDialog != null && progressDialog!!.isShowing)
progressDialog!!.dismiss()
}
//彈出原生交互界面
fun AffirmDialogShow(title: String, content: String) {
AlertDialog.Builder(this)
.setCancelable(false)
.setTitle(title)
.setMessage(content)
.setNegativeButton("取消") { dialogInterface, i -> dialogInterface.dismiss() }
.setPositiveButton("確認(rèn)") { dialogInterface, i ->
okOperation()//點(diǎn)擊確認(rèn)操作
dialogInterface.dismiss()
}.show()
}
abstract fun createPresenter():T//初始化Presenter
protected open fun okOperation() {}
override fun onDestroy() {
super.onDestroy()
mPresenter!!.detachView()
mContextView = null
// Log.i("xxxxxxxxxxxxxxx","xxxxxxxxxxxxxxxxxxx")
}
}
BaseModel
在BaseModel中主要的實(shí)現(xiàn)的需要傳入?yún)?shù)的寫入溯香,數(shù)據(jù)的請(qǐng)求鲫构,Rxjava的線程切換。
abstract class BaseModel <T:BaseBean>{
//傳入的key
var mParams:HashMap<String,String>?=HashMap()
//請(qǐng)求接口
open fun PostParams(){
ServiceParams(Params()!!)
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe (object : Subscriber<BaseBean>() {
override fun onCompleted() {
Completed()
}
override fun onError(e: Throwable?) {
FailedOperation(e)
}
override fun onNext(o: BaseBean) {
// val message = o.message
//mOnLoginListenr?.LoginSuccess()
SuccessOperation(o)
}
})
}
open fun Completed() {
}
//請(qǐng)求失敗
abstract fun FailedOperation(e: Throwable?)
//請(qǐng)求成功
abstract fun SuccessOperation(o: BaseBean)
abstract fun Params(): HashMap<String, String>?
//得到Observable
abstract fun ServiceParams(params: HashMap<String, String>): Observable<T>
open fun ClearHashMap(){
if (mParams!!.size>0)
mParams!!.clear()
}
}
BasePresenter
在BasePresenter中比較簡(jiǎn)單玫坛,需要實(shí)現(xiàn)綁定和解綁函數(shù)结笨,attachView,detachView湿镀,在這里使用了弱引用炕吸,內(nèi)存不夠時(shí)釋放,
abstract class BasePresenter<T:BaseView> {
var mViewRef:WeakReference<T>?=null
fun attachView(view:T){
mViewRef=WeakReference<T>(view)
}
fun detachView(){
if(mViewRef!=null){
mViewRef!!.clear()
mViewRef==null
}
}
}
RetrofitManager
RetrofitManager是對(duì)Retrofit的一個(gè)封裝勉痴,在這個(gè)類中我們完成了對(duì)OKHTTP和Retrofit的一個(gè)初始化赫模,以及調(diào)用
class RetrofitManager : Interceptor {
//長(zhǎng)緩存有效期為7天
val CACHE_STALE_LONG="60 * 60 * 24 * 7"
var mOkHttpClient: OkHttpClient? = null
var service: RetrofitService? = null
init {
initOkHttpclient()
var retrofit = Retrofit.Builder()
.baseUrl(Constants.BASE_URL)
.client(mOkHttpClient)
.addCallAdapterFactory(RxJavaCallAdapterFactory.create())
.addConverterFactory(GsonConverterFactory.create())
.build()
service = retrofit.create(RetrofitService::class.java)
}
//相當(dāng)于java中的靜態(tài)內(nèi)部類
companion object {
fun builder() :RetrofitManager {
return RetrofitManager()
}
}
//配置緩存策略
fun initOkHttpclient() {
//log信息攔截器
val interceptor = HttpLoggingInterceptor()
interceptor.level = HttpLoggingInterceptor.Level.BODY
if (mOkHttpClient == null) {
mOkHttpClient = OkHttpClient.Builder()
// .cache(cache)
.retryOnConnectionFailure(true)
.addNetworkInterceptor(this)
.addInterceptor(this)
.connectTimeout(15, TimeUnit.SECONDS)
.readTimeout(10000L, TimeUnit.MILLISECONDS)//讀操作超時(shí)時(shí)間
.cookieJar(CookiesManager())
.build()
}
}
//這是對(duì)cookie的一個(gè)長(zhǎng)期持有
private inner class CookiesManager : CookieJar {
private val cookieStore = PersistentCookieStore(MyApplication.getInstance().applicationContext)
override fun saveFromResponse(url: HttpUrl, cookies: List<Cookie>?) {
if (cookies != null && cookies.size > 0) {
for (item in cookies) {
cookieStore.add(url, item)
}
}
}
override fun loadForRequest(url: HttpUrl): List<Cookie> {
return cookieStore.get(url)
}
}
override fun intercept(chain: Interceptor.Chain?): Response {
var request = chain!!.request()
if (!NetWorkUtil.isNetWorkConnected()) {
request = request.newBuilder().cacheControl(CacheControl.FORCE_CACHE).build()
}
var response = chain.proceed(request)
if (NetWorkUtil.isNetWorkConnected()) {
var cacheControl: String = request.cacheControl().toString()
return response.newBuilder().header("Cache-Control", cacheControl)
.removeHeader("Pragma").build()
} else {
return response.newBuilder().header("Cache-Control", "public, only-if-cached, max-stale=" + CACHE_STALE_LONG)
.removeHeader("Pragma").build()
}
}
}
BaseBean
在實(shí)際開發(fā)中,每一個(gè)接口都有一些固定字段蒸矛,可以提取出來(lái)生成BaeBean嘴瓤,其余Bean文件集成BaseBean即可扫外,這里我就不貼出BaseBean了,因?yàn)榻涌谠蚶啵珺aseBean應(yīng)該是不一樣的筛谚。
RecyclerView
在這個(gè)框架中我是導(dǎo)入的第三方的XRecyclerView
compile 'com.jcodecraeer:xrecyclerview:1.3.2'
在Android中出現(xiàn)最多的列表,功能大概就是上拉刷新停忿,下拉加載驾讲,沒(méi)有更多數(shù)據(jù),當(dāng)然還有很多異常處理席赂,比如網(wǎng)絡(luò)異常吮铭,加載失敗等等異常,在這里對(duì)這些異常處理沒(méi)怎么作為颅停,大家后面自行補(bǔ)充谓晌。
實(shí)現(xiàn)步奏
在接口ListView中我們聲明了上拉下拉等方法
interface ListViews:BaseView {
fun loadMore( data:ArrayList<*>)//加載更多
fun showRefresh(data: ArrayList<*>)//上拉刷新
fun hasNoMoreData()//沒(méi)有更多
}
在activity中實(shí)現(xiàn),在代碼中的注釋都比較詳細(xì)癞揉,所以我在文字中就不多作闡述
class ListActivity : BaseActivity<ListViews,ListPresenter>(),ListViews {
var mAdapter:MyAdapter?=null
var mList:ArrayList<MyPaperBean.PageResultsBean>?= ArrayList()
//綁定布局
override fun bindLayout(): Int {
return R.layout.activity_list
}
override fun initData() {
//初始化xrecyclerview
val layoutManager = LinearLayoutManager(this)
layoutManager.orientation = LinearLayoutManager.VERTICAL
mRecyclerview.layoutManager=layoutManager
mRecyclerview.setRefreshProgressStyle(ProgressStyle.BallSpinFadeLoader)
mRecyclerview.setLoadingMoreProgressStyle(ProgressStyle.Pacman)
mRecyclerview.setArrowImageView(R.drawable.iconfont_downgrey)
}
override fun initListener() {
//RecyclerView的上拉和下拉
mRecyclerview.setLoadingListener(object :XRecyclerView.LoadingListener{
override fun onLoadMore() {
mPresenter!!.getMoreData()
}
override fun onRefresh() {
//showToast("ssss")
mPresenter!!.getRefreshData()
}
})
mAdapter= MyAdapter(mList)
mRecyclerview.adapter=mAdapter
mRecyclerview.refresh()
}
//實(shí)現(xiàn)接口里面的方法
@Suppress("UNCHECKED_CAST")
override fun loadMore(data: ArrayList<*>) {
mList!!.addAll(data as ArrayList<MyPaperBean.PageResultsBean>)
mAdapter!!.notifyDataSetChanged()
mRecyclerview.loadMoreComplete()
}
@Suppress("UNCHECKED_CAST")
override fun showRefresh(data: ArrayList<*>) {
// showToast("xxxxxxxxx")
mList!!.addAll(data as ArrayList<MyPaperBean.PageResultsBean>)
mAdapter!!.notifyDataSetChanged()
mRecyclerview.refreshComplete()
}
override fun hasNoMoreData() {
mRecyclerview.setNoMore(true)
mAdapter!!.notifyDataSetChanged()
}
//得到Presenter
override fun createPresenter(): ListPresenter{
return ListPresenter(this)
}
}
同第一篇文章一樣纸肉,實(shí)現(xiàn)Model和Presenter。這里就把Model貼出來(lái)喊熟,其他的等我第三篇的源碼鏈接吧柏肪。
interface ListModel {
fun getMoreData()//上拉加載
fun getRefreshDta()//下拉刷新
fun showNetError()//網(wǎng)絡(luò)錯(cuò)誤
fun showDataError()//加載錯(cuò)誤
fun loadComplete(loadedListener: LoadComplete)//數(shù)據(jù)加載完成
interface LoadComplete{
fun getDataRefresh(mDatas:ArrayList<*>)
fun getDataMore(mDatas:ArrayList<*>)
fun getDataFailed(baseBean: BaseBean)
fun hasNoMoreData()
}
}
后續(xù)
這篇文章只完成了幾個(gè)基類的封裝和RecyclerView的初步實(shí)現(xiàn),在下篇文章中將完成對(duì)RecyclerView的封裝芥牌,欲知后事如何烦味,請(qǐng)聽下回分解......