前言
應(yīng)公司需求,重構(gòu)項(xiàng)目,特搭建一套適合自己公司項(xiàng)目的框架
一.所需掌握的技能點(diǎn)
A.組件化開(kāi)發(fā):
你需要了解以下知識(shí)點(diǎn)
1.gradle基礎(chǔ)
2.注解生成器(apt)
3.注解的使用
3.路由器(本項(xiàng)目使用的是阿里開(kāi)源的arouter)
4.思維導(dǎo)圖工具的使用(目的:是用來(lái)分離項(xiàng)目的業(yè)務(wù))
B.MVP框架:
你需要了解以下知識(shí)點(diǎn)
1.注解的使用
2.泛型的使用
3.動(dòng)態(tài)代理設(shè)計(jì)模式
4.抽象工廠設(shè)計(jì)模式
5.單列設(shè)計(jì)模式
6.mvp設(shè)計(jì)思想,簡(jiǎn)單框架的搭建
C.網(wǎng)絡(luò)框架:
你需要了解以下知識(shí)點(diǎn)
1.rxjava,rxandroid,rxlifecycle,rxpermissions(rx系列基本使用)
2.rxjava的操作符compose,等等。。
2.okhttp使用,欄截器,加密等
3.retrofit 基本使用,與rxjava配合的使用
ok,如果以上知識(shí)點(diǎn)差不多掌握那么這套框架你分分鐘搞定。寫(xiě)這篇文章主要目的,一是為了記錄自己所學(xué)知識(shí),二是為了鞏固自己。如有寫(xiě)的不好的地方,請(qǐng)各位朋友多多海涵。
附上githubdemo https://github.com/yangyoupeng/Componentized
二.搭建框架時(shí)遇到的問(wèn)題:
A組件化遇到的問(wèn)題
1.組件開(kāi)發(fā)時(shí),我需要什么環(huán)境
2.組件之間AndroidManifest合并問(wèn)題
3.各module如何通信(如:activity,fragment)
4.retrofit,api接口怎么定義?
B MVP框架搭建遇到的問(wèn)題
1.presenter層如何拿到view的引用 ,當(dāng)view層銷(xiāo)毀時(shí)產(chǎn)生內(nèi)存泄漏,如何解決
2.view 為空時(shí),p層怎么處理
3.使用動(dòng)態(tài)代理生成P層,在view層如何用注解拿到p層
C 網(wǎng)絡(luò)框架搭建遇到的問(wèn)題
1.封裝retrofit時(shí),okhttp,如果封裝公共參數(shù)
2.如果動(dòng)態(tài)生成api接口類(lèi)
3.如果封裝rxjava的Observable
4.rxlifecycle綁定
進(jìn)入正題
三.組件化
我們?cè)賮?lái)回顧下問(wèn)題
1.組件開(kāi)發(fā)時(shí),我需要什么環(huán)境
2.組件之間AndroidManifest合并問(wèn)題
3.各module如何通信(如:activity,fragment)
4.retrofit,api接口怎么定義?
1.組件開(kāi)發(fā)時(shí),我需要什么環(huán)境
組件開(kāi)發(fā)環(huán)境主要是利用:組件模式和集成模式的轉(zhuǎn)換
apply plugin: ‘com.android.application’這個(gè)是application屬性,可以獨(dú)立運(yùn)行的Android程序,也就是我們的APP
apply plugin: ‘com.android.library’library屬性,不可以獨(dú)立運(yùn)行,一般是Android程序依賴(lài)的庫(kù)文件;
module的屬性是在每個(gè)組件的 build.gradle 文件中配置的,當(dāng)我們?cè)诮M件模式開(kāi)發(fā)時(shí),業(yè)務(wù)組件應(yīng)處于application屬性,這時(shí)的業(yè)務(wù)組件就是一個(gè) Android App,可以獨(dú)立開(kāi)發(fā)和調(diào)試;而當(dāng)我們轉(zhuǎn)換到集成模式開(kāi)發(fā)時(shí),業(yè)務(wù)組件應(yīng)該處于 library 屬性,這樣才能被我們的“app殼工程”所依賴(lài),組成一個(gè)具有完整功能的APP;
但是我們?nèi)绾巫尳M件在這兩種模式之間自動(dòng)轉(zhuǎn)換呢?總不能每次需要轉(zhuǎn)換模式的時(shí)候去每個(gè)業(yè)務(wù)組件的 Gralde 文件中去手動(dòng)把 Application 改成 library 吧?如果我們的項(xiàng)目只有兩三個(gè)組件那么這個(gè)辦法肯定是可行的,手動(dòng)去改一遍也用不了多久,但是在大型項(xiàng)目中我們可能會(huì)有十幾個(gè)業(yè)務(wù)組件,再去手動(dòng)改一遍必定費(fèi)時(shí)費(fèi)力,這時(shí)候就需要程序員發(fā)揮下懶的本質(zhì)了。
試想,我們經(jīng)常在寫(xiě)代碼的時(shí)候定義靜態(tài)常量,那么定義靜態(tài)常量的目的什么呢?當(dāng)一個(gè)常量需要被好幾處代碼引用的時(shí)候,把這個(gè)常量定義為靜態(tài)常量的好處是當(dāng)這個(gè)常量的值需要改變時(shí)我們只需要改變靜態(tài)常量的值,其他引用了這個(gè)靜態(tài)常量的地方都會(huì)被改變,做到了一次改變,到處生效;根據(jù)這個(gè)思想,那么我們就可以在我們的代碼中的某處定義一個(gè)決定業(yè)務(wù)組件屬性的常量,然后讓所有業(yè)務(wù)組件的build.gradle都引用這個(gè)常量,這樣當(dāng)我們改變了常量值的時(shí)候,所有引用了這個(gè)常量值的業(yè)務(wù)組件就會(huì)根據(jù)值的變化改變自己的屬性;可是問(wèn)題來(lái)了?靜態(tài)常量是用Java代碼定義的,而改變組件屬性是需要在Gradle中定義的,Gradle能做到嗎?
Gradle自動(dòng)構(gòu)建工具有一個(gè)重要屬性,可以幫助我們完成這個(gè)事情。每當(dāng)我們用AndroidStudio創(chuàng)建一個(gè)Android項(xiàng)目后,就會(huì)在項(xiàng)目的根目錄中生成一個(gè)文件 gradle.properties,我們將使用這個(gè)文件的一個(gè)重要屬性:在Android項(xiàng)目中的任何一個(gè)build.gradle文件中都可以把gradle.properties中的常量讀取出來(lái);那么我們?cè)谏厦嫣岬浇鉀Q辦法就有了實(shí)際行動(dòng)的方法,首先我們?cè)趃radle.properties中定義一個(gè)常量值 isModule(是否是組件開(kāi)發(fā)模式,true為是,false為否):
每次更改“isModule”的值后,需要點(diǎn)擊 "Sync Project" 按鈕
isModule=false
然后我們?cè)跇I(yè)務(wù)組件的build.gradle中讀取 isModule,但是 gradle.properties 還有一個(gè)重要屬性: gradle.properties 中的數(shù)據(jù)類(lèi)型都是String類(lèi)型,使用其他數(shù)據(jù)類(lèi)型需要自行轉(zhuǎn)換;也就是說(shuō)我們讀到 isModule 是個(gè)String類(lèi)型的值,而我們需要的是Boolean值,代碼如下:
if (isModule.toBoolean()) {
apply plugin: 'com.android.application'
} else {
apply plugin: 'com.android.library'
}
這樣我們第一個(gè)問(wèn)題就解決了,當(dāng)然了 每次改變isModule的值后,都要同步項(xiàng)目才能生效;
2.組件之間AndroidManifest合并問(wèn)題
在 AndroidStudio 中每一個(gè)組件都會(huì)有對(duì)應(yīng)的 AndroidManifest.xml,用于聲明需要的權(quán)限、Application、Activity、Service、Broadcast等,當(dāng)項(xiàng)目處于組件模式時(shí),業(yè)務(wù)組件的 AndroidManifest.xml 應(yīng)該具有一個(gè) Android APP 所具有的的所有屬性,尤其是聲明 Application 和要 launch的Activity,但是當(dāng)項(xiàng)目處于集成模式的時(shí)候,每一個(gè)業(yè)務(wù)組件的 AndroidManifest.xml 都要合并到“app殼工程”中,要是每一個(gè)業(yè)務(wù)組件都有自己的 Application 和 launch的Activity,那么合并的時(shí)候肯定會(huì)沖突,試想一個(gè)APP怎么可能會(huì)有多個(gè) Application 和 launch 的Activity呢?
但是大家應(yīng)該注意到這個(gè)問(wèn)題是在組件開(kāi)發(fā)模式和集成開(kāi)發(fā)模式之間轉(zhuǎn)換引起的問(wèn)題,而在上一節(jié)中我們已經(jīng)解決了組件模式和集成模式轉(zhuǎn)換的問(wèn)題,另外大家應(yīng)該都經(jīng)歷過(guò)將 Android 項(xiàng)目從 Eclipse 切換到 AndroidStudio 的過(guò)程,由于 Android 項(xiàng)目在 Eclipse 和 AndroidStudio開(kāi)發(fā)時(shí) AndroidManifest.xml 文件的位置是不一樣的,我們需要在build.gradle 中指定下 AndroidManifest.xml 的位置,AndroidStudio 才能讀取到 AndroidManifest.xml,這樣解決辦法也就有了,我們可以為組件開(kāi)發(fā)模式下的業(yè)務(wù)組件再創(chuàng)建一個(gè) AndroidManifest.xml,然后根據(jù)isModule指定AndroidManifest.xml的文件路徑,讓業(yè)務(wù)組件在集成模式和組件模式下使用不同的AndroidManifest.xml,這樣表單沖突的問(wèn)題就可以規(guī)避了。

上圖是組件化項(xiàng)目中一個(gè)標(biāo)準(zhǔn)的業(yè)務(wù)組件目錄結(jié)構(gòu),首先我們?cè)趍ain文件夾下創(chuàng)建一個(gè)module文件夾用于存放組件開(kāi)發(fā)模式下業(yè)務(wù)組件的 AndroidManifest.xml,而 AndroidStudio 生成的 AndroidManifest.xml 則依然保留,并用于集成開(kāi)發(fā)模式下業(yè)務(wù)組件的表單;然后我們需要在業(yè)務(wù)組件的 build.gradle 中指定表單的路徑,代碼如下:
sourceSets {
main {
if (isModule.toBoolean()) {
manifest.srcFile 'src/main/module/AndroidManifest.xml'
} else {
manifest.srcFile 'src/main/AndroidManifest.xml'
}
}
}
這樣在不同的開(kāi)發(fā)模式下就會(huì)讀取到不同的 AndroidManifest.xml ,然后我們需要修改這兩個(gè)表單的內(nèi)容以為我們不同的開(kāi)發(fā)模式服務(wù)。
首先是集成開(kāi)發(fā)模式下的 AndroidManifest.xml,前面我們說(shuō)過(guò)集成模式下,業(yè)務(wù)組件的表單是絕對(duì)不能擁有自己的 Application 和 launch 的 Activity的,也不能聲明APP名稱(chēng)、圖標(biāo)等屬性,總之a(chǎn)pp殼工程有的屬性,業(yè)務(wù)組件都不能有,下面是一份標(biāo)準(zhǔn)的集成開(kāi)發(fā)模式下業(yè)務(wù)組件的 AndroidManifest.xml:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.guiying.girls">
<application android:theme="@style/AppTheme">
<activity
android:name=".main.GirlsActivity"
android:screenOrientation="portrait" />
<activity
android:name=".girl.GirlActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar" />
</application>
</manifest>
我在這個(gè)表單中只聲明了應(yīng)用的主題,而且這個(gè)主題還是跟app殼工程中的主題是一致的,都引用了common組件中的資源文件,在這里聲明主題是為了方便這個(gè)業(yè)務(wù)組件中有使用默認(rèn)主題的Activity時(shí)就不用再給Activity單獨(dú)聲明theme了。
然后是組件開(kāi)發(fā)模式下的表單文件:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.guiying.girls">
<application
android:name="debug.GirlsApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/girls_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity
android:name=".main.GirlsActivity"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".girl.GirlActivity"
android:screenOrientation="portrait"
android:theme="@style/AppTheme.NoActionBar" />
</application>
</manifest>
組件模式下的業(yè)務(wù)組件表單就是一個(gè)Android項(xiàng)目普通的AndroidManifest.xml,這里就不在過(guò)多介紹了。
3.各module如何通信(如:activity,fragment)
在組件化開(kāi)發(fā)的時(shí)候,組件之間是沒(méi)有依賴(lài)關(guān)系,我們不能在使用顯示調(diào)用來(lái)跳轉(zhuǎn)頁(yè)面了,因?yàn)槲覀兘M件化的目的之一就是解決模塊間的強(qiáng)依賴(lài)問(wèn)題,假如現(xiàn)在要從A業(yè)務(wù)組件跳轉(zhuǎn)到業(yè)務(wù)B組件,并且要攜帶參數(shù)跳轉(zhuǎn),這時(shí)候怎么辦呢?而且組件這么多怎么管理也是個(gè)問(wèn)題,這時(shí)候就需要引入“路由”的概念了.
在這里我就不做過(guò)多介紹了,介紹一個(gè)阿里的開(kāi)源框架:ARouter
各位看官請(qǐng)自行去github查看,這里給張飛機(jī)票:https://github.com/alibaba/ARouter
4.retrofit,api接口怎么定義?
請(qǐng)求網(wǎng)絡(luò)基本每個(gè)模塊都需要用到,但各個(gè)模塊都不相互依賴(lài),這時(shí),我們的api接口怎么定義呢
不多說(shuō)直接上代碼



來(lái)我們看最后一張圖,這里我們傳入了一個(gè)class<T>這個(gè)是用來(lái)干嘛的呢,還是不費(fèi)話直接上代碼
A模塊下:

B模塊下

四.MVP框架:
首先貼出原文地址:http://blog.csdn.net/yulong0809/article/details/78622428
簡(jiǎn)單的封裝咱們就不講了,直接來(lái)個(gè)有逼格的。
首先講下封裝的步驟與思路:
1.創(chuàng)建簡(jiǎn)單的mvp2.通過(guò)注解生成presenter3.動(dòng)態(tài)創(chuàng)建 presenter工廠4.自定義工廠類(lèi)(創(chuàng)建不同的presenter)5.如何使用
1.簡(jiǎn)單mvp的實(shí)現(xiàn)
思路如下:
1、首先我們先定義一個(gè)接口,用來(lái)規(guī)定針對(duì)這個(gè)界面邏輯View需要作出的動(dòng)作的接口。
2、讓Activity實(shí)現(xiàn)這個(gè)接口中的方法,也就是V層
3、創(chuàng)建一個(gè)類(lèi),用來(lái)封裝之前的網(wǎng)絡(luò)請(qǐng)求過(guò)程,也就是M層
4、再創(chuàng)建一個(gè)類(lèi),用來(lái)處理M層和V層之間的通信,也就是P層
下面來(lái)實(shí)現(xiàn)一下:
1、首先我們先定義一個(gè)接口,用來(lái)規(guī)定針對(duì)這個(gè)界面邏輯View需要作出的動(dòng)作的接口。
/**
* <p>View接口的基類(lèi)</p>
*
* @author yangyoupeng
* @name IBaseView
*/
public interface IBaseView {
/**
* 用來(lái) 綁定view 生命周期,解決rxjava內(nèi)存泄露
*
* @param
* @return
*/
<T> ObservableTransformer<T, T> bindLifeycle();
/**
* 顯示正在加載
*/
void showProgress();
/**
* 隱藏正在加載
*/
void hideProgress();
}
2.定義一個(gè)presenter ,來(lái)用解偶
/**
* <p>Presenter的基類(lèi)</p>
*
* @author yangyoupeng 2018、4、24
* * 使用動(dòng)態(tài)代理模式設(shè)計(jì)basePresenter的初忠:
* 因?yàn)樵谑褂胢vp模式開(kāi)發(fā)中,會(huì)遇到一些問(wèn)題:
* 比如:activity持有presenter的引用,presenter持有view的引用 ,這就導(dǎo)致幾個(gè)問(wèn)題,
* 1.當(dāng)activity銷(xiāo)毀后,由于p持有activity的引用 導(dǎo)致activity無(wú)法釋放,最終會(huì)引用內(nèi)存泄漏
* <p>
* 2.p層處理完邏輯,調(diào)用v層來(lái)處理UI,怎么拿到V層的引用
* <p>
* 3.請(qǐng)求網(wǎng)絡(luò)時(shí),網(wǎng)絡(luò)不太好,在這個(gè)時(shí)候用戶沒(méi)等到請(qǐng)求完成退出該頁(yè)面,等獲取數(shù)據(jù)成功之后再拿V的引用 ,這個(gè)時(shí)候view 有可能被銷(xiāo)毀,v層的引用為空
*/
public abstract class BasePresenter<V extends IBaseView> {
/**
* 解決第一個(gè)問(wèn)題
* <p>
* 弱引用, 防止內(nèi)存泄漏
*/
private WeakReference<V> mWeakReference;
private V mProxyView;
/**
* 關(guān)聯(lián)V層和P層
*
*/
public void attatchView(V v) {
mWeakReference = new WeakReference<>(v);
MvpViewHandler viewHandler = new MvpViewHandler(mWeakReference.get());
mProxyView = (V) Proxy.newProxyInstance(v.getClass().getClassLoader(), v.getClass().getInterfaces(), viewHandler);
}
/**
* @return P層和V層是否關(guān)聯(lián).
*/
public boolean isViewAttached() {
return mWeakReference != null && mWeakReference.get() != null;
}
/**
* 斷開(kāi)V層和P層
* 在Acitivity的onDestory()中調(diào)用
*/
public void detachView() {
if (isViewAttached()) {
mWeakReference.clear();
mWeakReference = null;
}
}
/**
* 解決第二個(gè)問(wèn)題
*/
public V getView() {
return mProxyView;
}
/**
* Presenter被銷(xiāo)毀時(shí)調(diào)用
*/
public void onDestroyPersenter() {
Log.e("perfect-mvp","P onDestroy = ");
}
/**
* 在Presenter意外銷(xiāo)毀的時(shí)候被調(diào)用,它的調(diào)用時(shí)機(jī)和Activity、Fragment、View中的onSaveInstanceState
* 時(shí)機(jī)相同
*
*/
public void onSaveInstanceState(Bundle presenterBundle) {
Log.e("perfect-mvp","P onSaveInstanceState = ");
}
/**
* 動(dòng)態(tài)代理類(lèi)
*/
private class MvpViewHandler implements InvocationHandler {
private IBaseView mvpView;
MvpViewHandler(IBaseView mvpView) {
this.mvpView = mvpView;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//解決第三個(gè)問(wèn)題,如果V層沒(méi)被銷(xiāo)毀, 執(zhí)行V層的方法.
try {
if (isViewAttached()) {
return method.invoke(mvpView, args);
}
} catch (InvocationTargetException e){
throw e.getCause();
}
//P層不需要關(guān)注V層的返回值
return null;
}
}
}
3.創(chuàng)建建一個(gè)類(lèi),用來(lái)封裝之前的網(wǎng)絡(luò)請(qǐng)求過(guò)程,也就是M層
public class BaseModule {
public static FoundService createrRetrofit() {
return RetrofitManager.getInstance().getRetrofitService(FoundService.class);
}
}
這里就是網(wǎng)絡(luò)請(qǐng)求的封裝,這個(gè)下面再講。
好了,簡(jiǎn)單的mvp就寫(xiě)到這里,上面我注釋已經(jīng)寫(xiě)的很清楚了,在這就不多說(shuō)了,這里我就不介紹使用了。
下面咱們玩一點(diǎn)高逼格的
2.如何用注解生成presenter
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface CreatePresenter {
//這里的BaseMvpPresenter是自己封裝好的,可以根據(jù)項(xiàng)目需要訂制
//? extends BaseMvpPresenter 這指的是什么意思呢,
//?代表BaseMvpPresenter的子類(lèi) , extends代表用于返回參數(shù),如果是super代表傳參,
Class<? extends BaseMvpPresenter> value();
}
3.presenter工廠接口
為什么需要這個(gè)呢,因?yàn)槲覀儾恢纏resenter具體 是哪個(gè),所以需要拿到有注解的這個(gè)類(lèi),動(dòng)態(tài)創(chuàng)建presenter。
public interface PresenterMvpFactory<V extends BaseMvpView,P extends
BaseMvpPresenter<V>> {
/**
* 創(chuàng)建Presenter的接口方法
* @return 需要?jiǎng)?chuàng)建的Presenter
*/
P createMvpPresenter();
}
presenter工廠實(shí)現(xiàn)類(lèi)
**
* yangyoupeng on 2018/4/25.
* <p>
* 創(chuàng)建presenter
* 動(dòng)態(tài) 工廠的實(shí)現(xiàn)類(lèi)
*/
public class MvpPresenterFactroyImpl<V extends IBaseView, P extends BasePresenter<V>> implements IMvpPresenterFactroy<V, P> {
private final Class<P> mPresenterClass;
private MvpPresenterFactroyImpl(Class<P> presenterClass) {
this.mPresenterClass = presenterClass;
}
/**
* 根據(jù)注解創(chuàng)建Presenter的工廠實(shí)現(xiàn)類(lèi)
*
* @param aClass 需要?jiǎng)?chuàng)建Presenter的V層實(shí)現(xiàn)類(lèi)
* @param <V> 當(dāng)前View實(shí)現(xiàn)的接口類(lèi)型
* @param <P> 當(dāng)前要?jiǎng)?chuàng)建的Presenter類(lèi)型
* @return 工廠類(lèi)
*/
public static <V extends IBaseView, P extends BasePresenter<V>> MvpPresenterFactroyImpl creater(Class<?> aClass) {
//拿到創(chuàng)建presenter的注解
CreatePresenterAnnotation annotation = aClass.getAnnotation(CreatePresenterAnnotation.class);
Class<P> currentPresenter = null;
if (annotation != null) {
//獲取到具體的presenter
currentPresenter = (Class<P>) annotation.value();
}
//傳給有參構(gòu)造
return new MvpPresenterFactroyImpl(currentPresenter);
}
@Override
public P createMvpPresenter() {
try {
return mPresenterClass.newInstance();
} catch (Exception e) {
throw new RuntimeException("注解為空,請(qǐng)檢查類(lèi)上是否聲明了@CreatePresenterAnnotation(xxx,class)注解");
}
}
}
4.自定義工廠類(lèi)(創(chuàng)建不同的presenter)
1.創(chuàng)建不同的presenter接口,定義set,get方法,獲取不同的presenter
public interface IPresenterProxyFactroy<V extends IBaseView, P extends BasePresenter<V>> {
/**
* 設(shè)置創(chuàng)建Presenter的工廠
*
* @param presenterFactory PresenterFactory類(lèi)型
*/
void setPresenterFactory(IMvpPresenterFactroy<V, P> presenterFactory);
/**
* 獲取Presenter的工廠類(lèi)
*
* @return 返回PresenterMvpFactory類(lèi)型
*/
IMvpPresenterFactroy<V, P> getPresenterFactory();
/**
* 獲取創(chuàng)建的Presenter
*
* @return 指定類(lèi)型的Presenter
*/
P getMvpPresenter();
}
2.實(shí)現(xiàn)類(lèi),主要是獲取當(dāng)前presenter實(shí)列綁定view生命周期,并做了判斷處理,讓代碼更加健壯如:拋出異常
public class PresenterProxyFactroyImpl<V extends IBaseView, P extends BasePresenter<V>> implements IPresenterProxyFactroy<V, P> {
/**
* 獲取onSaveInstanceState中bundle的key
*/
private static final String PRESENTER_KEY = "presenter_key";
/**
* Presenter工廠類(lèi)
*/
private IMvpPresenterFactroy<V, P> mFactory;
private P mPresenter;
private Bundle mBundle;
private boolean mIsAttchView;
public PresenterProxyFactroyImpl(IMvpPresenterFactroy<V, P> presenterMvpFactory) {
this.mFactory = presenterMvpFactory;
}
@Override
public void setPresenterFactory(IMvpPresenterFactroy<V, P> presenterFactory) {
if (mPresenter != null) {
throw new IllegalArgumentException("這個(gè)方法只能在getMvpPresenter()之前調(diào)用,如果Presenter已經(jīng)創(chuàng)建則不能再修改");
}
this.mFactory = presenterFactory;
}
@Override
public IMvpPresenterFactroy<V, P> getPresenterFactory() {
return mFactory;
}
@Override
public P getMvpPresenter() {
if (mFactory != null) {
if (mPresenter == null) {
mPresenter = mFactory.createMvpPresenter();
}
}
Log.e("perfect-mvp", "Proxy getMvpPresenter = " + mPresenter);
return mPresenter;
}
/**
* 綁定Presenter和view
*/
public void onCreate(V mvpView) {
getMvpPresenter();
Log.e("perfect-mvp","Proxy onCreate");
if (mPresenter != null && !mIsAttchView) {
mPresenter.attatchView(mvpView);
mIsAttchView = true;
}
}
/**
* 銷(xiāo)毀Presenter持有的View
*/
private void onDetachMvpView() {
Log.e("perfect-mvp","Proxy onDetachMvpView = ");
if (mPresenter != null && mIsAttchView) {
mPresenter.detachView();
mIsAttchView = false;
}
}
/**
* 銷(xiāo)毀Presenter
*/
public void onDestroy() {
Log.e("perfect-mvp","Proxy onDestroy = ");
if (mPresenter != null ) {
onDetachMvpView();
mPresenter.onDestroyPersenter();
mPresenter = null;
}
}
/**
* 意外銷(xiāo)毀的時(shí)候調(diào)用
* @return Bundle,存入回調(diào)給Presenter的Bundle和當(dāng)前Presenter的id
*/
public Bundle onSaveInstanceState() {
Log.e("perfect-mvp","Proxy onSaveInstanceState = ");
Bundle bundle = new Bundle();
getMvpPresenter();
if(mPresenter != null){
Bundle presenterBundle = new Bundle();
//回調(diào)Presenter
mPresenter.onSaveInstanceState(presenterBundle);
bundle.putBundle(PRESENTER_KEY,presenterBundle);
}
return bundle;
}
/**
* 意外關(guān)閉恢復(fù)Presenter
* @param savedInstanceState 意外關(guān)閉時(shí)存儲(chǔ)的Bundler
*/
public void onRestoreInstanceState(Bundle savedInstanceState) {
Log.e("perfect-mvp","Proxy onRestoreInstanceState = ");
Log.e("perfect-mvp","Proxy onRestoreInstanceState Presenter = " + mPresenter);
mBundle = savedInstanceState;
}
}
5.如何使用
1.創(chuàng)建一個(gè)baseMvp類(lèi)
2.創(chuàng)建代理對(duì)象
3.在activity不同的生命周期調(diào)用代理對(duì)象的生命周期,實(shí)時(shí)綁定
/**
* yangyoupeng on 2018/4/25.
* <p>
* 想要使用mvp,需要繼承此BaseMvpActivity
* <p>
* TODO:注意 需要?jiǎng)?chuàng)建 presenter,必需要添加注解 @CreatePresenterAnnotation(xxx.class)
*/
public abstract class BaseMvpActivity<V extends IBaseView, P extends BasePresenter<V>> extends BaseActivity
implements IPresenterProxyFactroy<V, P>, IBaseView{
private static final String PRESENTER_SAVE_KEY = "presenter_save_key";
/**
*1. 創(chuàng)建被代理對(duì)象,傳入默認(rèn)Presenter的工廠
*/
private PresenterProxyFactroyImpl<V, P> mProxy = new PresenterProxyFactroyImpl<>(MvpPresenterFactroyImpl.<V, P>creater(getClass()));
private LoadingDialog mLoadingDialog;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
mProxy.onCreate((V) this);
super.onCreate(savedInstanceState);
if (savedInstanceState != null) {
mProxy.onRestoreInstanceState(savedInstanceState.getBundle(PRESENTER_SAVE_KEY));
}
mLoadingDialog = new LoadingDialog(this);
}
@Override
protected void onResume() {
super.onResume();
Log.e("perfect-mvp", "V onResume");
// mProxy.onResume((V) this);
}
@Override
protected void onDestroy() {
super.onDestroy();
Log.e("perfect-mvp", "V onDestroy = ");
mProxy.onDestroy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Log.e("perfect-mvp", "V onSaveInstanceState");
outState.putBundle(PRESENTER_SAVE_KEY, mProxy.onSaveInstanceState());
}
@Override
public void setPresenterFactory(IMvpPresenterFactroy<V, P> presenterFactory) {
Log.e("perfect-mvp", "V setPresenterFactory");
mProxy.setPresenterFactory(presenterFactory);
}
@Override
public IMvpPresenterFactroy<V, P> getPresenterFactory() {
Log.e("perfect-mvp", "V getPresenterFactory");
return mProxy.getPresenterFactory();
}
@Override
public P getMvpPresenter() {
Log.e("perfect-mvp", "V getMvpPresenter");
return mProxy.getMvpPresenter();
}
/**
* 綁定生命周期
*/
@Override
public <T> ObservableTransformer<T, T> bindLifeycle() {
return this.bindToLifecycle();
}
@Override
public void showProgress() {
if (mLoadingDialog != null) {
mLoadingDialog.show();
}
}
@Override
public void hideProgress() {
if (mLoadingDialog != null) {
mLoadingDialog.dismiss();
}
}
2.通過(guò)我們之前寫(xiě)的注解獲取presenter實(shí)列,做用在類(lèi)上
@CreatePresenterAnnotation(ProductDetailActivityPresenter.class)
public class ProductDetailActivity extends BaseProductActivity<IProductDetailActivityContract.View,
ProductDetailActivityPresenter>implements IProductDetailActivityContract.View {
@BindView(R2.id.product_detail_toolbar)
TitleBar mToolbar;
@BindView(R2.id.first)
FrameLayout mFirst;
@BindView(R2.id.second)
FrameLayout mSecond;
@BindView(R2.id.product_detail_layout)
DragLayout mProductDetailLayout;
@BindView(R2.id.iv_calculator)
ImageView mIvCalculator;
@BindView(R2.id.btn_invest)
Button mBtnInvest;
private String mProductId;
private static final String TAG = "ProductDetailActivity";
private String mProductFoot;
@Override
public int setLayoutId() {
return R.layout.activity_product_detail;
}
這里我講解一下
@CreatePresenterAnnotation(ProductDetailActivityPresenter.class):注解生成presenter實(shí)列
IProductDetailActivityContract.View,這個(gè)是契約類(lèi),用來(lái)管理view,presenter接口,google推薦使用方法。
ProductDetailActivityPresenter:這個(gè)是具體的presenter
3.創(chuàng)建契約類(lèi)
/**
*用來(lái)管理view,presenter接口,google推薦使用方法。
*/
public interface IProductDetailActivityContract {
interface View extends IBaseView {
void isCertification(InvestmentActivityBean result);
}
abstract class Presenter extends BasePresenter<View> {
public abstract void getInvestData(String productId);
}
}
4.presenter 的實(shí)現(xiàn)
/**
* yangyoupeng on 2018/5/2.
*/
public class ProductDetailActivityPresenter extends IProductDetailActivityContract.Presenter {
@Override
public void getInvestData(String productId) {
BaseModule.createrRetrofit()
.getInvestRecord(ProductListParameter.getProductDetailParameter(productId))
.compose(RxSchedulers.observableIO2Main(getView()))
.subscribe(new ProgressObserver<InvestmentActivityBean>(this) {
@Override
public void onSuccess(InvestmentActivityBean result) {
getView().isCertification(result);
}
});
}
}
IProductDetailActivityContract.Presenter :這個(gè)也就是契約類(lèi)里面的presenter抽象類(lèi)
好了,基本的使用寫(xiě)完了,不知道我有沒(méi)有寫(xiě)明白,如有不太明白的地方,歡迎留言一起討論。
C.網(wǎng)絡(luò)框架:
網(wǎng)絡(luò)框架封裝,網(wǎng)上的文章一大把,在這里我也把這個(gè)封裝框架放上來(lái),并在組件化mvp中如果去使用它。
1.retrofit管理類(lèi)
2.異常管理
3.封裝線程的切換
4. observer封裝,如請(qǐng)求服務(wù)器時(shí),顯現(xiàn)dialog,成功隱藏dialog
5. 在組件化mvp中綁定生命周期
1.retrofit管理類(lèi)
/**
* yangyoupeng on 2018/4/12.
* <p>
* rxjava+retrofit+框架封裝
*/
public class RetrofitManager {
/**
* 保存一個(gè)retrofit的實(shí)例,通過(guò)吸(baseUrl來(lái)獲?。? */
private HashMap<String, Retrofit> mRetrofitHashMap = new HashMap<>();
private static final int DEFAULT_MILLISECONDS = 60000; //默認(rèn)的超時(shí)時(shí)間
/**
* 內(nèi)部類(lèi)單列設(shè)計(jì)模式
*/
private RetrofitManager() {
}
private static class RetrofitManagerInstance {
private final static RetrofitManager RETROFIT_MANAGER = new RetrofitManager();
}
public static RetrofitManager getInstance() {
return RetrofitManagerInstance.RETROFIT_MANAGER;
}
/**
* 獲取retrofit的實(shí)例
*
* @return Retrofit
*/
private Retrofit getRetrofit(String baseurl) {
Retrofit retrofit;
if (mRetrofitHashMap.containsKey(baseurl)) {
retrofit = mRetrofitHashMap.get(baseurl);
} else {
retrofit = createrRetrofit(baseurl);
}
return retrofit;
}
/**
* 創(chuàng)建retrofit
*
* @return Retrofit
*/
private Retrofit createrRetrofit(String baseurl) {
OkHttpClient httpClient = new OkHttpClient().newBuilder()
.readTimeout(DEFAULT_MILLISECONDS, TimeUnit.SECONDS)
.connectTimeout(DEFAULT_MILLISECONDS, TimeUnit.SECONDS)
.writeTimeout(DEFAULT_MILLISECONDS, TimeUnit.SECONDS)
.addNetworkInterceptor(new InterceptorUtil().HeaderInterceptor(BaseApplication.getInstance()))//添加其他攔截器
.addInterceptor(InterceptorUtil.LogInterceptor())//添加日志攔截器
.retryOnConnectionFailure(true)
.build();
return new Retrofit.Builder()
.baseUrl(baseurl)
.addConverterFactory(GsonConverterFactory.create())
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.client(httpClient)
.build();
}
/**
*根據(jù)各模塊業(yè)務(wù)接口 獲取不同的retrofit service接口對(duì)象
*/
public <T> T getRetrofitService(Class<T> cls) {
return createrRetrofit(BaseApi.getBaseUrl()).create(cls);
}
}
2.異常管理
public class ExceptionUtil {
private static final String TAG = "ExceptionUtil";
private final static int UnknownHostException = 1000;
private final static int SocketTimeoutException = 2000;
private final static int JSONException = 3000;
private final static int ServiceException = 500;
private final static int CustomerException = 400;
private final static int RedirectException = 300;
private final static int NoLoginException = 401;
public static int exceptionHandler(Throwable e) {
int code = 0;
if (e instanceof UnknownHostException) {
code = UnknownHostException;
} else if (e instanceof SocketTimeoutException) {
code = SocketTimeoutException;
} else if (e instanceof HttpException) {
HttpException httpException = (HttpException) e;
code = convertCode(httpException);
} else if (e instanceof ParseException || e instanceof JSONException
|| e instanceof com.google.gson.JsonIOException) {
code = JSONException;
}
return code;
}
private static int convertCode(HttpException httpException){
int code;
if (httpException.code() >= 500 && httpException.code() < 600) {
code = ServiceException;
} else if (httpException.code() >= 400 && httpException.code() < 500) {
if(httpException.code() == 401){
code = NoLoginException;
} else {
code = CustomerException;
}
} else if (httpException.code() >= 300 && httpException.code() < 400) {
code = RedirectException;
} else {
code = httpException.code();
}
return code;
}
public static String getMsg(int code){
String errorMsg = "網(wǎng)絡(luò)不給力";
switch (code){
case UnknownHostException:
errorMsg = "網(wǎng)絡(luò)不給力";
break;
case SocketTimeoutException:
errorMsg = "請(qǐng)求網(wǎng)絡(luò)超時(shí)";
break;
case JSONException:
errorMsg = "數(shù)據(jù)解析錯(cuò)誤";
break;
case ServiceException:
errorMsg = "服務(wù)器處理請(qǐng)求出錯(cuò)";
break;
case CustomerException:
errorMsg = "服務(wù)器無(wú)法處理請(qǐng)求";
break;
case RedirectException:
errorMsg = "請(qǐng)求被重定向到其他頁(yè)面";
break;
case NoLoginException:
errorMsg = "請(qǐng)重新登錄";
break;
}
return errorMsg;
}
**
* yangyoupeng on 2018/4/12.
* <p>
* 異常處理類(lèi)
*/
public class RxExceptionUtil {
private static final String TAG = "RxExceptionUtil";
public static String exceptionHandler(Throwable e) {
String errorMsg = "未知錯(cuò)誤";
if (e instanceof UnknownHostException) {
errorMsg = "網(wǎng)絡(luò)不可用";
} else if (e instanceof SocketTimeoutException) {
errorMsg = "請(qǐng)求網(wǎng)絡(luò)超時(shí)";
} else if (e instanceof HttpException) {
HttpException httpException = (HttpException) e;
errorMsg = convertStatusCode(httpException);
} else if (e instanceof ParseException || e instanceof JSONException
|| e instanceof com.google.gson.JsonIOException) {
errorMsg = "數(shù)據(jù)解析錯(cuò)誤";
}
return errorMsg;
}
private static String convertStatusCode(HttpException httpException){
Log.d(TAG, "convertStatusCode: "+httpException.code());
String msg;
if (httpException.code() >= 500 && httpException.code() < 600) {
msg = "服務(wù)器處理請(qǐng)求出錯(cuò)";
} else if (httpException.code() >= 400 && httpException.code() < 500) {
if(httpException.code() == 401){
// throw new UnLoginException();
msg = "請(qǐng)重新登錄";
} else {
msg = "服務(wù)器無(wú)法處理請(qǐng)求";
}
} else if (httpException.code() >= 300 && httpException.code() < 400) {
msg = "請(qǐng)求被重定向到其他頁(yè)面";
} else {
msg = httpException.message();
}
return msg;
}
}
3.封裝線程的切換
/**
* yangyoupeng on 2018/4/20.
* <p>
* 切換線程 與綁定rxlifeycle 生命周期
*/
public class RxSchedulers {
public static <T> ObservableTransformer<T, T> observableIO2Main(IBaseView iBaseView) {
return upstream -> upstream.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.compose(iBaseView.bindLifeycle());
}
}
在這里我用了lamada表達(dá)式,大家有空可以去了解下
3.observer封裝,如請(qǐng)求服務(wù)器時(shí),顯現(xiàn)dialog,成功隱藏dialog
**
* yangyoupeng on 2018/4/12.
* <p>
* 請(qǐng)求服務(wù)器,返回的數(shù)據(jù)做同一處理
*/
public abstract class BaseObserver<T> implements Observer<BaseResponse<T>> {
private static final String TAG = "BaseObserver";
@Override
public void onSubscribe(Disposable d) {
}
@Override
public final void onNext(BaseResponse<T> tBaseResponse) {
Log.d(TAG, "服務(wù)器返回的code: " + tBaseResponse.getCode());
switch (tBaseResponse.getCode()) {
case 200:
onSuccess(tBaseResponse.getData());
break;
default:
onFailure(new Exception(tBaseResponse.getMsg()), tBaseResponse.getCode(), tBaseResponse.getMsg());
break;
}
}
@Override
public void onError(@NonNull Throwable e) {
int code = ExceptionUtil.exceptionHandler(e);
Log.d(TAG, "錯(cuò)誤信息---" + e.getMessage() + "-----錯(cuò)誤碼: " + code);
String msg = ExceptionUtil.getMsg(code);
onFailure(e, code, msg);
}
@Override
public void onComplete() {
}
public abstract void onSuccess(T result);
public void onFailure(Throwable e, int code, String errorMsg) {
Log.d(TAG, "onFailure: 什么錯(cuò)誤: " + e + "-------錯(cuò)誤信息:" + errorMsg);
if (code == 401) {
EventBus.getDefault().post(new EventType(EventType.EVENT_NO_LOGIN));
if (e instanceof HttpException) {
HttpException httpException = (HttpException) e;
HttpUrl url = httpException.response().raw().request().url();
String s = String.valueOf(url);
Log.d(TAG, "onFailure: "+s);
if(!s.contains("api/account/index")){
ARouter.getInstance().build(RouterPath.LOGIN_REGISTER_ACTIVITY).navigation();
}
}
} else if (code == 402) {//實(shí)名認(rèn)證
EventBus.getDefault().post(new EventType(EventType.TO_REA_NNAME_AUTHENTICATION));
} else {
ToastUtils.showShortToast(errorMsg);
}
}
}
/**
* yangyoupeng on 2018/4/12.
* <p>
* 擴(kuò)展類(lèi),用來(lái)調(diào)用請(qǐng)求網(wǎng)絡(luò)時(shí)的進(jìn)度條
*/
public abstract class ProgressObserver<T> extends BaseObserver<T> {
private BasePresenter mBasePresenter;
protected ProgressObserver(BasePresenter basePresenter) {
this.mBasePresenter = basePresenter;
}
@Override
public void onSubscribe(@NonNull Disposable d) {
if (!d.isDisposed()) {
mBasePresenter.getView().showProgress();
}
}
@Override
public void onComplete() {
if (mBasePresenter.isViewAttached()) {
mBasePresenter.getView().hideProgress();
}
}
@Override
public void onError(@NonNull Throwable e) {
super.onError(e);
if (mBasePresenter.isViewAttached()) {
mBasePresenter.getView().hideProgress();
}
}
}
5.在組件化mvp中綁定生命周期
1.首先需要在這里定義bindLifeycle返回值是ObservableTransformer
public interface IBaseView {
/**
* 用來(lái) 綁定view 生命周期,解決rxjava內(nèi)存泄露
*
* @param
* @return
*/
<T> ObservableTransformer<T, T> bindLifeycle();
2.當(dāng)前baeActivity 繼承RxAppCompatActivity
SuppressLint("Registered")
public abstract class BaseActivity extends RxAppCompatActivity {
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(setLayoutId());
GetuiPushClient.getInstance().init(getApplication());
ButterKnife.bind(this);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); // 禁止所有的activity橫屏
ViewManager.getInstance().addActivity(this);
initView(savedInstanceState);
initData();
EventBus.getDefault().register(this);
}
實(shí)現(xiàn)IBaseView方法,綁定生命周期
public abstract class BaseMvpActivity<V extends IBaseView, P extends BasePresenter<V>> extends BaseActivity
implements IPresenterProxyFactroy<V, P>, IBaseView{
private static final String PRESENTER_SAVE_KEY = "presenter_save_key";
/**
* 綁定生命周期
*/
@Override
public <T> ObservableTransformer<T, T> bindLifeycle() {
return this.bindToLifecycle();
}
3.在網(wǎng)絡(luò)請(qǐng)求中通過(guò).compose()去切換線程并綁定生命周期
@Override
public void getData(String productId, String type) {
BaseModule.createrRetrofit()
.getInvestRecord(ProductListParameter.getProductDetailParameter(productId))
.compose(RxSchedulers.observableIO2Main(getView()))
.subscribe(new ProgressObserver<InvestmentActivityBean>(this) {
@Override
public void onSuccess(InvestmentActivityBean result) {
getView().displayData(result, type);
}
});
}
到這里就結(jié)束啦,細(xì)節(jié)實(shí)在太多,沒(méi)辦法一篇文章寫(xiě)出來(lái)。所以代碼我都貼出來(lái)了,如有不太明白的地方歡迎一起探討交流, QQ: 1003605461。