android mvp的好處,網上一搜一大堆,相對於一開始普通的在activity中處理所有的不管是網絡請求還是頁面渲染,最大的好處是簡潔了,廢話不多說,看代碼
這里網絡請求使用了兩種,一種是自己封裝的okhttp,一種是retrofit+rxjava,可以看出retrofit+rxjava的鏈式調用和普通的okhttp的區別
mvp,m-model 處理數據,v-activity渲染展示,p-persenter 用於連接m和v,其中又引入鍥約類的概念,用於管理這三個所有的接口。
先看代碼,
,為了方便我直接放在一個包里了,可以看到 有TestActivity,(mvp-v),TestModel(mvp-m),TestPersenter(mvp-p),其中TestContract就是契約類,用於管理用到的所有接口,多了一個TestCallback用於使用自己封裝的okhttp回調,使用retrofit+rxjava時可以省略,這其中也有人習慣把TestModel省略,直接在Persenter中處理數據然后在view中返回。
先看契約類,其中BaseView可以提取一些公共的方法
public interface TestContract { interface TestModel{ void getData(String id,TestCallback callback); Observable<HomePage> getData(); } interface TestPersenter{ void getData(String id); }
interface TestView extends BaseView {
void SetData(HomePage homePage);
}
}
public interface BaseView { void Toast(String s); /** * 綁定Android生命周期 防止RxJava內存泄漏 * * @param <T> * @return */ <T> AutoDisposeConverter<T> bindAutoDispose(); }
可以清楚的看到,model,persenter,view使用到的接口。
再看activity中,implements TestContract.TestView接口,必須實現接口中的方法----SetData,定義了一個按鈕,一個TextView,點擊按鈕,獲取數據,顯示在TextView中,其中TestPersenter testPersenter = new TestPersenter(this);體現了persenter的連接作用,獲取到實例,調用persenter中的getData方法,
public class TestActivity extends BaseActivity implements TestContract.TestView {
TestPersenter testPersenter = new TestPersenter(this);
@BindView(R.id.button)
Button button;
@BindView(R.id.testview)
TextView testview;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
ButterKnife.bind(this);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
testPersenter.getData("1");
}
});
}
@Override
public void SetData(HomePage homePage) {
testview.setText(homePage.getMessage());
}
@Override
public void Toast(String s) {
super.Toast(s);
}
}
public class BaseActivity extends AppCompatActivity implements BaseView { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_base2); Window window = getWindow(); window.addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS); getSupportActionBar().hide(); ImmersionBar.with(this) .statusBarColor(R.color.bar) //狀態欄顏色,不寫默認透明色 .statusBarDarkFont(true) //原理:如果當前設備支持狀態欄字體變色,會設置狀態欄字體為黑色,如果當前設備不支持狀態欄字體變色,會使當前狀態欄加上透明度,否則不執行透明度 .fitsSystemWindows(true) .keyboardEnable(true) .init(); } @Override protected void onDestroy() { super.onDestroy(); // 必須調用該方法,防止內存泄漏 ImmersionBar.destroy(this,null); } /** * 綁定生命周期 防止MVP內存泄漏 * * @param <T> * @return */ @Override public <T> AutoDisposeConverter<T> bindAutoDispose() { return AutoDispose.autoDisposable(AndroidLifecycleScopeProvider .from(this, Lifecycle.Event.ON_DESTROY)); } @Override public void Toast(String s) { } }
TestPersenter,首先implements 接口,實現接口中的方法---getData,其次拿到了model和view,在getData方法中,調用model獲取數據,調用view的setData方法展示數據到頁面,從這里也可以看出persenter的連接作用,連接model和view。
public class TestPersenter implements TestContract.TestPersenter{ TestContract.TestModel model ; TestContract.TestView testView; public TestPersenter(TestContract.TestView testView) { this.testView = testView; this.model = new TestModel(); } @Override public void getData(String id) { model.getData("1", new TestCallback() { @Override public <T> void success(T enty) { testView.SetData((HomePage) enty); } @Override public void error(String msg) { } }); } }
model:同樣implements接口,實現接口中的方法getData,第一個方法是使用自己封裝的okhttp網絡類,在這里就看出TestCallback 的作用了,訪問接口獲取數據后,通過TestCallback 返回,TestCallback 中只定義了兩個簡單的,一個成功時的回調,一個失敗時的回調
public class TestModel implements TestContract.TestModel {
@Override
public void getData(String id, TestCallback callback) {
new OkHttpUtil().getJson(HttpUrl.homePage, new OkHttpUtil.HttpCallBack() {
@Override
public void onSusscess(String data) throws JSONException, ParseException {
HomePage homePage = new Gson().fromJson(data,HomePage.class);
if(homePage.isSuccess()){
callback.success(homePage);
}else{
callback.error(homePage.getMessage());
}
}
@Override
public void onError(String meg) {
super.onError(meg);
callback.error(meg);
}
});
}
@Override
public Observable<HomePage> getData() {
return RetrofitClient.getInstance().getApi().GetData();
}
}
public interface TestCallback { <T> void success(T enty); void error(String msg); }
使用retrofit+rxjava,可以看到,省略了TestCallback回調,直接鏈式調用,onNext中調用了view的setData方法顯示數據。
public class TestPersenter implements TestContract.TestPersenter{ TestContract.TestModel model ; TestContract.TestView testView; public TestPersenter(TestContract.TestView testView) { this.testView = testView; this.model = new TestModel(); } @Override public void getData(String id) { // model.getData("1", new TestCallback() { // @Override // public <T> void success(T enty) { // testView.SetData((HomePage) enty); // } // // @Override // public void error(String msg) { // // } // }); model.getData() .compose(RxScheduler.Obs_io_main()) .to(studyView.bindAutoDispose()) .subscribe(new Observer<HomePage>() { @Override public void onSubscribe(@NonNull Disposable d) { } @Override public void onNext(@NonNull HomePage homePage) { testView.SetData(homePage); } @Override public void onError(@NonNull Throwable e) {
) } @Override public void onComplete() { } }); } }
retrofit的使用到的方法
public interface APIService {
/**
* 首頁數據
* @return
*/
@GET("app/home_page/queryList")
Observable<HomePage> GetData();
}
public class RetrofitClient { private static volatile RetrofitClient instance; private APIService apiService; private String baseUrl = "****"; private Retrofit retrofit; private OkHttpClient okHttpClient; private RetrofitClient() { } public static RetrofitClient getInstance() { if (instance == null) { synchronized (RetrofitClient.class) { if (instance == null) { instance = new RetrofitClient(); } } } return instance; } /** * 設置Header * * @return */ private Interceptor getHeaderInterceptor() { return new Interceptor() { @Override public Response intercept(@NonNull Chain chain) throws IOException { Request original = chain.request(); Request.Builder requestBuilder = original.newBuilder(); //添加Token // .header("token", ""); Request request = requestBuilder.build(); return chain.proceed(request); } }; } /** * 設置攔截器 打印日志 * * @return */ private Interceptor getInterceptor() { HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor(); //顯示日志 interceptor.setLevel(HttpLoggingInterceptor.Level.BODY); return interceptor; } public OkHttpClient getOkHttpClient() { if (okHttpClient == null) { //如果為DEBUG 就打印日志 if (BuildConfig.DEBUG) { okHttpClient = new OkHttpClient().newBuilder() //設置Header .addInterceptor(getHeaderInterceptor()) //設置攔截器 .addInterceptor(getInterceptor()) .build(); } else { okHttpClient = new OkHttpClient().newBuilder() //設置Header .addInterceptor(getHeaderInterceptor()) .build(); } } return okHttpClient; } public APIService getApi() { //初始化一個client,不然retrofit會自己默認添加一個 if (retrofit == null) { retrofit = new Retrofit.Builder() //設置網絡請求的Url地址 .baseUrl(baseUrl) //設置數據解析器 .addConverterFactory(GsonConverterFactory.create()) //設置網絡請求適配器,使其支持RxJava與RxAndroid .addCallAdapterFactory(RxJava3CallAdapterFactory.create()) .client(getOkHttpClient()) .build(); } //創建—— 網絡請求接口—— 實例 if (apiService==null){ apiService = retrofit.create(APIService.class); } return apiService; } }
public class RxScheduler { /** * 統一線程處理 * * @param <T> 指定的泛型類型 * @return FlowableTransformer */ public static <T> FlowableTransformer< T, T> Flo_io_main() { return new FlowableTransformer<T, T>() { @Override public Publisher<T> apply(Flowable<T> upstream) { return upstream.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } }; } /** * 統一線程處理 * * @param <T> 指定的泛型類型 * @return ObservableTransformer */ public static <T> ObservableTransformer<T, T> Obs_io_main() { return new ObservableTransformer<T, T>() { @Override public ObservableSource<T> apply( Observable<T> upstream) { return upstream.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } }; } }
public interface BaseView { void Toast(String s); /** * 綁定Android生命周期 防止RxJava內存泄漏 * * @param <T> * @return */ <T> AutoDisposeConverter<T> bindAutoDispose(); }
//okhttp3 implementation 'com.squareup.okhttp3:okhttp:4.2.0' implementation "com.squareup.okhttp3:logging-interceptor:3.10.0" implementation 'com.google.code.gson:gson:2.8.6' //retrofit2 implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' implementation 'com.squareup.retrofit2:adapter-rxjava3:2.9.0' //AutoDispose解決RxJava內存泄漏 implementation 'com.uber.autodispose2:autodispose:2.0.0' implementation 'com.uber.autodispose2:autodispose-android:2.0.0' implementation 'com.uber.autodispose2:autodispose-lifecycle:2.0.0' implementation 'com.uber.autodispose2:autodispose-androidx-lifecycle:2.0.0'
// 基礎依賴包,必須要依賴
implementation 'com.gyf.immersionbar:immersionbar:3.0.0-beta07'
// fragment快速實現(可選)
implementation 'com.gyf.immersionbar:immersionbar-components:3.0.0-beta07'
至此,mvp框架結束,mvp增加了接口,使頁面和數據處理分開,層次分明,后期好維護。在較小項目中,就幾個頁面,不必使用框架,也不必為了框架而使用,適合項目的才是最好的。