本项目旨在搭建一个简易的Android开发结构,避免新手开发时出现代码混乱的问题,如有不同意见欢迎评论区提出包含一个基础的框架搭建,讲解都在注释里 一、主要功能
- 提供基础的MVP结构,并集成相关的初始化操作提供基础的网络管理框架,更方便的进行网络请求和管理提供日志打印管理,可以在logcat自动打印指定级别的http日志,方便调试提供简单的页面示例 SampleActivity
// blankj 工具包,包含了相当多的功能,强推 implementation 'com.blankj:utilcodex:1.30.6' // retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' implementation 'com.jakewharton.retrofit:retrofit2-rxjava2-adapter:1.0.0' implementation 'com.squareup.retrofit2:converter-gson:2.9.0' // rx java implementation 'io.reactivex.rxjava2:rxandroid:2.1.1' implementation "me.jessyan:rxerrorhandler:2.1.1" // butterKnife 控件绑定 implementation 'com.jakewharton:butterknife:10.2.3' annotationProcessor 'com.jakewharton:butterknife-compiler:10.2.3'2. 代码结构图 3. MVP 相关代码
MVP 接口定义
public interface IModel {
void onDestroy();
}
public interface IView {
default void showLoading(){
}
default void hideLoading() {
}
default void showMessage(String msg) {
ToastUtils.showShort(msg);
}
}
public interface IPresenter {
void addDisposable(Disposable... disposables);
default void initDataReq() {
}
void onDestroy();
}
baseModel 实现
import com.blankj.utilcode.util.ToastUtils; import io.reactivex.Observable; import io.reactivex.android.schedulers.AndroidSchedulers; import java.lang.reflect.ParameterizedType; import java.util.Objects; public abstract class baseModelimplements IModel { protected P mPresenter; Class
serviceClass; @SuppressWarnings("unchecked") public baseModel(P mPresenter) { this.mPresenter = mPresenter; try { // 这一段代码,就是反射,通过泛型,获取指定的类 ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass(); if (type == null) { throw new RuntimeException("运行异常,初始化失败: " + getClass().getSimpleName()); } serviceClass = (Class) type.getActualTypeArguments()[1]; } catch (Exception e) { e.printStackTrace(); } } //使用Retrofit获取了指定接口的实例 //通过Service执行某一个请求时,拼接Url并执行网络访问,并将返回结果按指定格式解析并返回 protected S obtainService() { return NetManager.getInstance().bindService(serviceClass);//谁拿到 ,谁指定Service } protected boolean checkCode(CommonResBean> bean) { String needDisplay = bean.checkCode(); if (needDisplay == null) { return true; } // 向 presenter 中 增加通知错误信息线程 mPresenter.addDisposable(Observable.just(needDisplay) .observeOn(AndroidSchedulers.mainThread()) .filter(Objects::nonNull) .subscribe(ToastUtils::showShort)); return false; } @Override public void onDestroy() { mPresenter = null; } }
basePresenter 实现
import io.reactivex.disposables.CompositeDisposable; import io.reactivex.disposables.Disposable; import java.lang.reflect.ParameterizedType; //basePresenter 两个泛型,前者为视图的,后者为数据源的 public abstract class basePresenterimplements IPresenter { protected V mView;//V 泛型变量 protected M mModel;//M 泛型变量 // 这是一个集合,用来控制生命周期 private CompositeDisposable compositeDisposable; @SuppressWarnings("unchecked") public basePresenter(V mView) { this.mView = mView; // 保存了上级 View try { // 一个泛型Model 实例 ParameterizedType type = (ParameterizedType) getClass().getGenericSuperclass(); if (type == null) { throw new RuntimeException("运行异常,初始化失败: " + getClass().getSimpleName()); } Class classM = (Class ) type.getActualTypeArguments()[1]; this.mModel = (M) classM.getConstructors()[0].newInstance(this); } catch (Exception e) { e.printStackTrace(); } compositeDisposable = new CompositeDisposable(); } //从子管理传参到这里,再for循环出来数据 给compositeDisposable public void addDisposable(Disposable... disposables) { if (compositeDisposable == null) { return; } for (Disposable disposable : disposables) { compositeDisposable.add(disposable); } } @Override public void onDestroy() { mView = null; if (mModel != null) { mModel.onDestroy();//不等于空,就销毁 mModel = null; } // 在合适的时机取消未结束的网络请求 // 取消所有未完成的网络请求 // 因为视图已经销毁了,如果继续下去,会崩溃 if (compositeDisposable != null) { compositeDisposable.dispose(); compositeDisposable = null; } } }
baseActivity/baseFragment 实现
import android.annotation.SuppressLint; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import androidx.annotation.CallSuper; import androidx.appcompat.app.AppCompatActivity; import butterknife.ButterKnife; public abstract class baseActivityextends AppCompatActivity implements IView, InitialPro
{ protected P mPresenter; protected View mContentView; @SuppressLint("InflateParams") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //Event后,在后台能接到消息; 要用Manager里面的eventMManager mPresenter = initPresenter();//被 泛型的某一个Presenter来初始化IPresenter 在Activity中 mContentView = LayoutInflater.from(this).inflate(getContentViewId(), null, false); setContentView(mContentView); ButterKnife.bind(this, mContentView); initView(); initData(); } @CallSuper protected void initData() { mPresenter.initDataReq(); } //解绑 @Override protected void onDestroy() { super.onDestroy(); if (mPresenter != null) { mPresenter.onDestroy(); mPresenter = null; } } }
import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import androidx.annotation.CallSuper; import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.fragment.app.Fragment; import butterknife.ButterKnife; public abstract class baseFragment4. Retrofit 部分关键代码extends Fragment implements IView, InitialPro
{ protected P mPresenter; protected View mContentView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mPresenter = initPresenter();//被泛型的某一个Presenter来初始化(引入)IPresenter 在Fragment中 } @Nullable @Override public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { mContentView = inflater.inflate(getContentViewId(), container, false); // base View 主要做的,绑定 Presenter,初始化结构,绑定ButterKnife // ButterKnife 就是做了一个视图绑定,不用再findviewbyid ButterKnife.bind(this, mContentView); initView(); initData(); return mContentView; } @CallSuper protected void initData() { // 可以看到,在View 基类中,视图创建好了之后 // 会告知Presenter可以准备请求网络数据了 // 因为如果过早,视图还没创建,如果网络请求好了,那就会崩溃 // 所以这个时机让Presenter请求网络 哦。明白了。是的。。 mPresenter.initDataReq(); } @Override public void onDestroy() { super.onDestroy(); // 在视图销毁时,释放资源 if (mPresenter != null) { // 告知Presenter释放 mPresenter.onDestroy(); mPresenter = null; } } }
import com.blankj.utilcode.util.GsonUtils;
import com.jakewharton.retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
import okhttp3.OkHttpClient;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import java.util.concurrent.TimeUnit;
public class NetManager {
private static NetManager netManager;
Retrofit retrofit;
private NetManager() {
// 我们使用的是Retrofit代管网络,这是他的初始化方法
retrofit = new Retrofit.Builder()
.client(obtainOKHttpClient())
// 这是基础url,会跟 Service 中的 拼接
.baseUrl("https://www.7timer.info")
.addConverterFactory(GsonConverterFactory.create(GsonUtils.getGson()))
.addCallAdapterFactory(RxJava2CallAdapterFactory.create())
.build();
}
private OkHttpClient obtainOKHttpClient() {
return new OkHttpClient.Builder()
.callTimeout(10, TimeUnit.SECONDS)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(10, TimeUnit.SECONDS)
.writeTimeout(10, TimeUnit.SECONDS)
.addInterceptor(new RequestInterceptor(RequestInterceptor.Level.ALL))
.build();
}
public static NetManager getInstance() {
if (netManager == null) {
throw new RuntimeException("你还没有初始化 NetManager");
}
return netManager;
}
// 这两个操作,保证唯一,放到Application中
// 初始化,单例模式,保证唯一
public static void init(Context context) {
netManager = new NetManager();
}
// 释放资源
public static void release() {
if (netManager != null) {
netManager.retrofit = null;
netManager = null;
}
}
public T bindService(Class targetInterface) {
return retrofit.create(targetInterface);
}
}
三、使用示例
1. 声明要访问的网络接口
import io.reactivex.Observable;
import retrofit2.http.GET;
import retrofit2.http.Query;
public interface SampleServices {
@GET("/bin/api.pl")
Observable getWeather(
@Query("lon") double lon,
@Query("lat") double lat,
@Query("product") String pro,
@Query("output") String output
);
}
2. 创建SampleModel调用请求
import cn.lzd.mvp.base.struct.baseModel; import cn.lzd.mvp.base.struct.IPresenter; import io.reactivex.Observable; public class SampleModel extends baseModel3. 创建Presenter管理请求,并分发数据{ public SampleModel(IPresenter mPresenter) { super(mPresenter); } public Observable getWeather() { return obtainService().getWeather( 113.17, 23.09, "astro", "json" ); } }
import cn.lzd.mvp.base.net.RxUtils; import cn.lzd.mvp.base.struct.basePresenter; public class SamplePresenter extends basePresenter4. 创建View显示视图{ public SamplePresenter(SampleActivity mView) { super(mView); } void reqWeather() { addDisposable(mModel.getWeather() .compose(RxUtils.applySchedulers(mView)) .subscribe(weatherData -> mView.onReceiveWeatherData(weatherData.getDatas()))); } }
@SuppressLint("NonConstantResourceId")
public class SampleActivity extends baseActivity {
@BindView(R.id.reqResult)
TextView tvReqResult;
@BindView(R.id.loadingBG)
View loadingBG;
@BindView(R.id.loadingProgress)
ProgressBar loadingProgress;
@BindView(R.id.request)
View request;
@Override
public int getContentViewId() {
return R.layout.activity_sample;
}
@Override
public void initView() {
super.initView();
tvReqResult.setMovementMethod(ScrollingMovementMethod.getInstance());
}
@OnClick({R.id.request, R.id.loadingBG})
public void onClick(View view) {
// 对不同的控件做点击事件处理
switch (view.getId()) {
case R.id.request: {
tvReqResult.setText("");
view.setEnabled(false);
mPresenter.reqWeather();
break;
}
case R.id.loadingBG:{
ToastUtils.showShort("请等待……");
break;
}
}
}
void onReceiveWeatherData(List weatherData) {
StringBuilder stringBuilder = new StringBuilder();
for (SampleBeans.DayData dayData : weatherData) {
stringBuilder.append(GsonUtils.toJson(dayData)).append("nn");
}
tvReqResult.setText(stringBuilder);
request.setEnabled(true);
}
@Override
public void showLoading() {
loadingBG.setVisibility(View.VISIBLE);
loadingProgress.setVisibility(View.VISIBLE);
}
@Override
public void hideLoading() {
loadingBG.setVisibility(View.GONE);
loadingProgress.setVisibility(View.GONE);
}
}
四、关于Observable数据流向的一个简要图示
五、运行结果示例
相关示例代码下载链接:MVP_DEMO



