Android MVP框架 详细代码
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增加了接口,使页面和数据处理分开,层次分明,后期好维护。在较小项目中,就几个页面,不必使用框架,也不必为了框架而使用,适合项目的才是最好的。