什麼是AOP?
在講解GoMVP框架的使用之前,我們先了解一下什麼是AOP。
面向切面程式設計
AOP —— Aspect Oriented Program,即面向切面程式設計,面向切面程式設計是一種思想,如同物件導向程式設計一樣,都是思想。
一、GoMVP的使用
1、新增依賴與外掛
主工程中gradle新增:
buildscript {
dependencies {
classpath 'com.android.tools.build:gradle:3.1.3'
classpath 'com.hujiang.aspectjx:gradle-android-plugin-aspectjx:2.0.2'
}
}
複製程式碼
app工程中gradle:
apply plugin: 'com.android.application'
apply plugin: 'android-aspectjx'
複製程式碼
app新增GoMVP依賴:
dependencies {
implementation 'com.wookii.gomvp:gomvp:1.3.2'
}
複製程式碼
app新增AOP配置:
android{
aspectjx {
//AOP時,排除所有package路徑中包含`android.support`的class檔案及庫(jar檔案)
exclude 'android.support'
}
}
複製程式碼
Demo
public class AnnotationDemoActivity extends AppCompatActivity {
@BindView(R.id.button2)
Button button;
@BindView(R.id.button3)
Button button3;
@DataSource(RepositoryInjection.class)
private LifecyclePresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_demo);
}
/**
* test @GoBack
* @param bean
*/
@GoBack
public void hahaha(MarketBean bean) {
GoLog.E("MarketBean is backing:" + bean.getMessage());
}
@GoError
public void error(String errorMsg) {
GoLog.E("error is backing:" + errorMsg);
}
@OnClick({R.id.button2, R.id.button3})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.button2:
break;
case R.id.button3:
presenter.execute(new MarketPresenterAdapter());
break;
}
}
}
複製程式碼
也許目前這個Demo片段大家看起來難以消化,從它的一些註解能猜測到這是一個基於註解以及AOP實現的MVP框架,那麼接下來我們一步步拆分,還原,介紹GoMVP的使用。
2、初始化Retrofit
GoMVP的網路請求框架是基於Retrofit,RxJava,OkHttp的網路框架,為了框架的靈活性,框架本身並不包含Retrofit的建立,這個需要外部提供,也就是使用者自己的Retrofit。建立好後,留著待用。
public class MainRetrofit implements RetrofitConverter {
@Override
public String host() {
return ApiServer.URL_CONTRACT_NET;
}
@Override
public Retrofit createRetrofit() {
return XstoreRetrofitManager.getInstance().getRetrofit(host(), null);
}
}
複製程式碼
首先實現RetrofitConverter類,實現的第一個方法是指定網路請求的host,第二個方法建立一個Retrofit並且create。這裡的XstoreRetrofitManager是使用者自己的。
3、初始化資料倉儲
在MVP架構中,資料倉儲是必不可少的元件(Repository),我們先來建立它。
public class MarketRepository implements GoDataSource {
@Override
public <B> GoDataSource loadDataFromRepository(Observable<B> observable, Observer observer) {
observable.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(observer);
return this;
}
@Override
public GoCache getGoCache(Context context) {
return new DefaultGoCache(context);
}
//繫結RetrofitConverter,非常關鍵
@Override
public RetrofitConverter onCreateRetrofitConverter() {
return new MainRetrofit();
}
@Override
public <T> void targetClazz(Class<T> clazz) {
return MarketBean.class;
}
}
複製程式碼
作為使用了GoMVP的Repository,必須實現GoDataSource介面,這個介面返回了四個方法功能如下:
1、loadDataFromRepository方法:
當presenter發起操作時,這是核心方法,治理返回了觀察者和被觀察者,發揮你的想象力可以在這裡做一些業務邏輯的處理
2、getGoCache方法:
使用者需要在這裡返回一個快取物件,預設使用由框架DefaultGoCache,後面會對快取的擴充套件進行講解。
3、onCreateRetrofitConverter方法:
最為關鍵,這個方法裡返回的就是我們第二步建立的MainRetrofit物件,這樣資料倉儲和具體的Retrofit進行了繫結。
4、targetClazz方法:
會接收到一個class物件,這個class物件通常情況下是個JavaBean,這是由使用者 去指定的,指定的地方在Presenter中,有些時候請求返回的Bean並不是我們想要的,可以通過指定的bean做業務上的強轉,還是看具體業務你用不用的上了。
4、建立Presenter擴充套件
在傳統的設計中Presenter的擴充套件都是通過繼承來完成的,在GoMVP中摒棄了這樣的方式,是通過PresenterAdapter去進行擴充套件(如果看到這裡比較迷糊,下一先跳過這一部分看一下示例再反過頭來看這部分內容)。
public class MarketPresenterAdapter extends PresenterAdapter{
@Override
public Observable onCreateObservable(Context context, RetrofitConverter retrofitConverter) {
Retrofit retrofit = retrofitConverter.createRetrofit();
ApiServer apiServer = retrofit.create(ApiServer.class);
HashMap<String, Object> map = new HashMap<>();
map.put("請求引數1",0);
map.put("請求引數2","123");
Observable<HttpResult<SecretKeyBean>> observable = apiServer.getSecretKey(map);
return observable;
}
@Override
public Pair onSuccessCodePair() {
return new Pair("success","true");
}
@Override
public String onErrorMessageKey() {
return "message";
}
@Override
public Class targetBeanType() {
return MarketBean.class;
}
}
複製程式碼
依舊是四個方法,我們分別解讀一下他們的作用
1、onCreateObservable方法:
該方法需要我們建立一個Observable物件,這個物件會在我們第三步建立的Repostory裡返回,方法體提供了一個RetrofitConverter物件,用來建立Observable,而這個RetrofitConverter是我們第二步建立出來,第三部繫結的。
2、targetBeanType方法
這個方法很關鍵,上面說到Repository的targetClazz方法會返回一個class,就是由這個方法指定的,除此之外它還有個更關鍵的功能,我下面再說。
其他兩個onSuccessCodePair和onErrorMessageKey方法現在用不到,後面再講。
5、使用示例
前面準備了怎麼多,我們開始使用。
/**
* Demo
*/
public class AnnoDemoActivity extends AppCompatActivity{
@BindView(R.id.button2)
Button button;
@BindView(R.id.button3)
Button button3;
@Presenter()
private LifecyclePresenter presenter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_demo);
//繫結資料倉儲
presenter.setRepository(new MarketRepository());
}
@GoBack
public void hahaha(MarketBean bean) {
GoLog.E("MarketBean is backing:" + bean.getValue().getMarketData().getAmountRtv());
}
@GoError
public void error(String errorMsg) {
GoLog.E("error is backing:" + errorMsg);
}
@OnClick({R.id.button2, R.id.button3})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.button2:
presenter.execute(new MarketPresenterAdapter());
break;
case R.id.button3:
break;
}
}
}
複製程式碼
6、使用@Presenter註解初始化Presenter
1、任意一個型別為LifecyclePresenter 的成員變數加上@Presenter註解,在Activity的onCreate時就會被建立好。
@Presenter
private LifecyclePresenter presenter;
複製程式碼
PS:之所以叫做LifecyclePresenter,是因為它具有生命週期感知功能,無需使用者關心生命週期的問題,比如釋放Presenter,同時它內部整合了BKnife,預設會管理BKnife的初始化與解除繫結等與生命週期相關的操作(使用者在自己的工程新增BKnife的依賴即可)。
2、在onCreate中繫結資料倉儲
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_simple_demo);
//繫結資料倉儲
presenter.setRepository(new MarketRepository());
}
複製程式碼
通過new的方式初始化MarketRepository是不優雅的,不建議這樣做,真正的做法是使用RepositoryInjection:下一節見。