从前根据参考各路大神的博客,以及本身对mvp的明确,早早就写了这种不成熟的联合模式(旧版),历时半年,他们终于进化了!
一、底子先容
1、什么是mvp
mvp是android开辟架构之一,MVP每个字母分别代表Model、View和Presenter。
①model负责处置惩罚网络数据的处置惩罚
②presenter是model和view的桥梁,负责与两端的通讯
③view是视图层
2、为什么有mvp
mvp的诞生得益于mvc,mvc确实贡献也不小而且也历经风雨,但mvc的耦合是在太严肃,因此mvp就诞生了。在mvp模式下,model和view是不直接举行交互的,而是要通过presenter作为桥梁,如许一来,各层的分工就更加明确,
①model不须要管ui长什么样,只要把对应的数据给到p即可,至于p是直接给v照旧处置惩罚了再给v,怎么给,都是p的变乱。
②而p这里,p不管model用的post照旧get,参数格式是什么,p只须要向m发起哀求,并在拿到结果后,把结果回调给v即可,不须要管v是要弹出对话框照旧吐司照旧跳转页面。
③v只须要把用户的动作或输入的内容给到p,期待p回应即可!
3、这个mvp和其他有些不太一样
这个mvp紧张照旧表现在p有写与众差别,p层拿到v的实例后,通过动态代理得到视图实例,view方法的实行又是交给InvocationHandler来处置惩罚的,如许可以有效制止view不存在时,还实行view方法。P中保举传入activity实例,着实要的是applicat和activity的name,临时还没想到更好的方法,就如许用着先。假如传入的参数不是activity大概没传参数,记得要在页面退出的该接纳的地方调用p的detachView方法。
二、实现步调
1、基于哪些底子?
起首肯定有个大条件,就是全部接口返回的数据格式,都是一样的,比如说现在我的接口返回数据格式是如许的
{ "code": 200, "message": "提交乐成"}又大概是如许的
{ "code": 200, "message": "", "data": { "userName": "张三", "headImage": "http://192.168.3.11/file/user/hf6d4g88a.jpg", "sex": 1, "bir": "2020-01-01" }}他们都有些共同点,如code和message,那么data就是泛型了!以是界说的相应体汲取的类为
public class CallResult<T> { public int code; public String message; public T data;}2、封装Retrofit
思量到偶然间须要在哀求的header中加各种数据,比如说appVersion等,并且上传文件宁静凡的接口超时时间一样寻常是差别的,因此就有了这种封装
2.1开始封装
import android.text.TextUtils;import android.util.Log;import com.example.mvp.OnHttpResultListener;import com.example.mvp.retrofit2.convert.MyConverterFactory;import java.util.ArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;import java.util.concurrent.TimeUnit;import okhttp3.Interceptor;import okhttp3.OkHttpClient.Builder;import retrofit2.Retrofit;import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;/** * @author Administrator */public class Retrofit2Manager { /** * 默认的哀求时间 */ private long timeOut = 20000L; /** * 监听哀求过程 */ private OnHttpResultListener onHttpResultListener; /** * 服务器所在 */ private final String baseUrl; /** * 哀求头 */ private final Map<String, String> map = new HashMap<>(); /** * 自界说拦截器 */ private final List<Class<? extends Interceptor>> interceptors = new ArrayList<>(); /** * 静态方法,入口 * * @param baseUrl 路径 * @return this */ public static Retrofit2Manager with(String baseUrl) { return new Retrofit2Manager(baseUrl); } /** * 私有构造方法 * * @param baseUrl 服务器路径 */ private Retrofit2Manager(String baseUrl) { this.baseUrl = baseUrl; } /** * 超时时间 * * @param timeOut timeOut * @return this */ public Retrofit2Manager setTimeOut(long timeOut) { this.timeOut = timeOut; return this; } /** * 监听哀求过程 * * @param onHttpResultListener onHttpResultListener * @return this */ public Retrofit2Manager setOnHttpResultListener(OnHttpResultListener onHttpResultListener) { this.onHttpResultListener = onHttpResultListener; return this; } /** * 添加自界说哀求头 * * @param key key * @param value value * @return this */ public Retrofit2Manager addHeadres(String key, String value) { if (TextUtils.isEmpty(key)) { return this; } if (TextUtils.isEmpty(value)) { value = ""; } map.put(key, value); return this; } public Retrofit2Manager add(Class<? extends Interceptor> mClass) { interceptors.add(mClass); return this; } /** * 返回retrofit2的实例 * * @return retrofit2 */ public Retrofit retrofit() { Builder okBuilder = new Builder(); okBuilder.readTimeout(this.timeOut, TimeUnit.MILLISECONDS); okBuilder.writeTimeout(this.timeOut, TimeUnit.MILLISECONDS); okBuilder.connectTimeout(this.timeOut, TimeUnit.MILLISECONDS); okBuilder.addInterceptor(new LogInterceptor(map, onHttpResultListener)); try { for (Class<? extends Interceptor> mClass : interceptors) { okBuilder.addInterceptor(mClass.newInstance()); } } catch (Exception e) { Log.e("mvp[error]", e.getMessage()); e.printStackTrace(); } return (new Retrofit.Builder()).client(okBuilder.build()) .baseUrl(this.baseUrl) //自界说分析 .addConverterFactory(MyConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .build(); }}2.2为什么要自界说分析?
当服务器返回的数据为
{ "code": 200, "message": "", "data": [ { "userName": "李四", "headImage": "http://192.168.3.11/file/user/hf6d4g3243288a.jpg", "sex": 1, "bir": "2020-01-01" }, { "userName": "张三", "headImage": "http://192.168.3.11/file/user/hf6d4g84348a.jpg", "sex": 2, "bir": "2020-01-17" }, { "userName": "王五", "headImage": "http://192.168.3.11/file/user/hf6d4345436g88a.jpg", "sex": 1, "bir": "2020-03-01" } ]}时,我们界说的实体类可以正常汲取数据。假如接口返回的数据是
{ "code": 401, "message": "登录状态已失效", "data": null}的时间,你会发现直接json转换闪退,由于null无法转换成list,因此我们要本身界说分析工厂,以下是部分代码
@Override public T convert(@NonNull ResponseBody value) { String str = ""; Object var3; try { if (value.contentLength() != 0L) { str = value.source().readUtf8(); var3 = this.convert(str, this.type); return (T) var3; } str = "{\"code\":90000,\"message\":\"服务器无相应\"}"; var3 = this.convert(str, CallResult.class); } catch (Exception var8) { //当转换出现非常,就用Void举行转换 Object var4 = this.convert(str, CallResult.class); return (T) var4; } finally { value.close(); } return (T) var3; }3、创建mvp的各种Base基类
3.1 model层BaseModel
OnHttpResultListener是本身界说的,用来汲取接口参数,对调试非常好用,上线版本可以忽略
import android.util.Log;import com.example.mvp.OnHttpResultListener;import com.example.mvp.retrofit2.Retrofit2Manager;import io.reactivex.Observable;import io.reactivex.android.schedulers.AndroidSchedulers;import io.reactivex.schedulers.Schedulers;public class BaseModel implements OnHttpResultListener { protected <T> T createService(String ip, Class<T> mClass) { return Retrofit2Manager.with(ip).setOnHttpResultListener(this).retrofit().create(mClass); } @Override public void onResponse(String method, String requestUrl, String requestHeaders, String requestParams, int responseCode, String responseData) { String sb = "\n【哀求方法】:" + method + "\n【哀求路径】:" + requestUrl + "\n【哀求头】:" + requestHeaders + "\n【哀求参数】:" + requestParams + "\n【返回参数】:" + responseData; Log.d("exccd(mvp-http)", sb); } /** * 发起哀求,并且在ui线程实行回调 * * @param observable observable * @param <T> 泛型 */ protected <T> Observable<T> callBackOnUi(Observable<T> observable) { return observable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()); } /** * 发起哀求,并且在新的子线程实行回调 * * @param observable observable * @param <T> 泛型 */ protected <T> Observable<T> callBackOnThread(Observable<T> observable) { return observable.subscribeOn(Schedulers.io()) .observeOn(Schedulers.newThread()); }}3.2 视图层IBaseView<T>
为了让ui实现这个回调更加简单,我这里将服务器返回的message和其他全部大概有的提示都通过s字段来返回了,因此不管是“登录状态已失效”照旧“网络毗连非常”,都是在s回调的。根据项目不用,有须要的可以拆分。
/** * ui回调 * * @param <T> 泛型 */public interface IBaseView<T> { /** * ui回调 * * @param b 是否哀求乐成 * @param i 范例 * @param s 形貌 * @param data 泛型 */ void onCallBack(boolean b, int i, String s, T data);}3.3 Presenter层
这一层最关键的是IBasePresenter和它的实现类BasePresenter
3.3.1 IBasePresenter
start方法是发起哀求的入口,使用时须要将model的方法传进去,然后跟视图绑定起来。
/** * presenter须要具备的底子方法 */public interface IBasePresenter { /** * 开始发起哀求 * * @param observable model层返回的obs * @param iBaseView 视图,回调 * @param <T> 泛型 */ <T> void start(Observable<CallResult<T>> observable, IBaseView<T> iBaseView); /** * 乐成回调 * * @param iBaseView 视图、回调 * @param data 数据 * @param <T> 泛型 */ <T> void viewCallBackSuccess(IBaseView<T> iBaseView, CallResult<T> data); /** * 错误回调 * * @param iBaseView 视图、回调 * @param e 错误信息 * @param <T> 泛型 */ <T> void viewCallBackError(IBaseView<T> iBaseView, Throwable e); /** * 解绑 */ void detachView();}3.3.2 BasePresenter
BasePresenter处置惩罚一些回调,将一些非正常接口哀求的结果转换成中文(指定形貌)在回调给view,这里的全部数据都是可以本身界说的,别的假如在某种环境下须要弹窗退出登录,发起您新建一个MyBasePresenter extend BasePresenter,然后重写onTokenErrorCallBack()即可,但判断的逻辑须要更改一下。
public abstract class BasePresenter<M> implements IBasePresenter { /** * 未授权登录,登录状态已失效 */ public static final int UNAUTHORIZED = 401; /** * 哀求乐成 */ public static final int SUCCESS = 200; /** * 哀求被禁止 */ public static final int FORBIDDEN = 403; /** * 接口失效 */ public static final int NOT_FOUND = 404; /** * 哀求超时 */ public static final int REQUEST_TIMEOUT = 408; /** * 服务器错误 */ public static final int INTERNAL_SERVER_ERROR = 500; /** * 错误的网关 */ public static final int BAD_GATEWAY = 502; /** * 服务器不可用 */ public static final int SERVICE_UNAVAILABLE = 503; /** * 网络超时 */ public static final int GATEWAY_TIMEOUT = 504; /** * 在默认线程回调 */ private boolean callBackInLoop = false; /** * 是否已经解绑了,制止重复解绑 */ private boolean isDttached = false; /** * model层 */ protected M module; /** * 视图 */ private final Map<Integer, IBaseView<?>> mapView = new HashMap<>(); /** * 视图引用 */ private final Map<Integer, WeakReference<?>> mapReference = new HashMap<>(); /** * 哀求对象 */ private final Map<Integer, Disposable> mapDisposables = new HashMap<>(); /** * 主线程 */ protected Handler handler; /** * 构造方法 * 您须要手动{@link #detachView()}解绑 */ public BasePresenter() { onCreate(null); } /** * 构造方法 * * @param activity activity的实例 */ public BasePresenter(Activity activity) { onCreate(activity); } /** * 构造方法 * * @param context 假如这是个activity的实例,那么不须要手动{@link #detachView()}即可解绑,否则您须要调用他 */ public BasePresenter(Context context) { if (context instanceof Activity) { onCreate((Activity) context); } else { onCreate(null); } } /** * 初始化方法 */ private void onCreate(Activity activity) { this.handler = new Handler(Looper.getMainLooper()); if (this.module == null) { this.module = this.createModel(); } if (activity != null) { String acName = activity.getLocalClassName(); Application app = activity.getApplication(); Application.ActivityLifecycleCallbacks callbacks = new Application.ActivityLifecycleCallbacks() { @Override public void onActivityCreated(Activity activity, Bundle bundle) { } @Override public void onActivityStarted(Activity activity) { } @Override public void onActivityResumed(Activity activity) { } @Override public void onActivityPaused(Activity activity) { } @Override public void onActivityStopped(Activity activity) { } @Override public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } @Override public void onActivityDestroyed(Activity activity) { if (acName.equals(activity.getLocalClassName())) { detachView(); app.unregisterActivityLifecycleCallbacks(this); } } }; app.registerActivityLifecycleCallbacks(callbacks); } } /** * 绑定 * * @param view 视图 */ @SuppressWarnings("all") private <T, V extends IBaseView<T>> void attachView(V view) { if (view != null) { WeakReference<V> weakReference = new WeakReference<V>(view); mapReference.put(view.hashCode(), weakReference); ClassLoader classLoader = view.getClass().getClassLoader(); Class<?>[] interfaces = view.getClass().getInterfaces(); InvocationHandler invocationHandler = new MvpViewHandler((IBaseView) weakReference.get()); IBaseView<T> v = (V) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler); mapView.put(view.hashCode(), v); } } /** * 是否在默认线程回调 * * @param callBackInLoop 假如是false,回调会在ui线程处置惩罚,否则就是在发起默认的线程回调 */ public void setCallBackInLoop(boolean callBackInLoop) { this.callBackInLoop = callBackInLoop; } /** * 页面是否已经不存在了 * * @param iBaseView 视图 * @param <T> 泛型 * @return true存在,则回调,否则忽略 */ protected <T> boolean isViewAttached(IBaseView<T> iBaseView) { if (iBaseView == null) { return false; } int key = iBaseView.hashCode(); IBaseView<?> view = mapView.get(key); WeakReference<?> weakReference = mapReference.get(key); return view != null && weakReference != null && weakReference.get() != null; } /** * 创建module * * @return M */ protected abstract M createModel(); /** * 哀求是否乐成 * * @param data 相应体 * @return 乐成true,失败false */ protected <T> boolean isSuccess(CallResult<T> data) { return data != null && data.code == SUCCESS; } /** * 开始发起哀求 * * @param observable model层返回的obs * @param baseView 视图、回调 * @param <T> 泛型 */ @Override public <T> void start(Observable<CallResult<T>> observable, IBaseView<T> baseView) { attachView(baseView); mapDisposables.put(baseView.hashCode(), observable .subscribe(data -> viewCallBackSuccess(baseView, data), e -> viewCallBackError(baseView, e))); } /** * 乐成回调 * * @param view 视图、回调 * @param data 数据 * @param <T> 泛型 */ @Override public <T> void viewCallBackSuccess(IBaseView<T> view, CallResult<T> data) { if (callBackInLoop) { _viewCallBackSuccess(view, data); } else { if (Looper.myLooper() == Looper.getMainLooper()) { _viewCallBackSuccess(view, data); } else { handler.post(() -> _viewCallBackSuccess(view, data)); } } } /** * 错误回调 * * @param view 视图、回调 * @param e 错误信息 * @param <T> 泛型 */ @Override public <T> void viewCallBackError(IBaseView<T> view, Throwable e) { if (callBackInLoop) { _viewCallBackError(view, e); } else { if (Looper.myLooper() == Looper.getMainLooper()) { _viewCallBackError(view, e); } else { handler.post(() -> _viewCallBackError(view, e)); } } } /** * 解绑 */ @Override public void detachView() { if (isDttached) { return; } isDttached = true;// this.module = null; this.handler.removeCallbacksAndMessages(null); for (WeakReference<?> weakReference : mapReference.values()) { if (weakReference != null) { weakReference.clear(); } } mapReference.clear(); mapView.clear(); try { for (Disposable disposable : mapDisposables.values()) { if (disposable != null && !disposable.isDisposed()) { disposable.dispose(); } } } catch (Exception e) { Log.e("mvp[error]", e.getMessage()); } } /** * 统一实行乐成回调,看{@link #viewCallBackSuccess} */ private <T> void _viewCallBackSuccess(IBaseView<T> view, CallResult<T> data) { if (data.code == UNAUTHORIZED) { onTokenErrorCallBack(data.message); } if (isViewAttached(view)) { view.onCallBack(data.code == SUCCESS, data.code, data.message, data.data); } } /** * 统一实行错误回调,看{@link #viewCallBackError} */ private <T> void _viewCallBackError(IBaseView<T> view, Throwable e) { if (isViewAttached(view)) { try { if (e instanceof HttpException) { HttpException httpException = (HttpException) e; switch (httpException.code()) { case UNAUTHORIZED: callBackError(view, "登录验证已过期"); onTokenErrorCallBack("登录验证已过期"); break; case INTERNAL_SERVER_ERROR: callBackError(view, "服务器错误"); break; case FORBIDDEN: case NOT_FOUND: callBackError(view, "无效的哀求"); break; case REQUEST_TIMEOUT: case GATEWAY_TIMEOUT: case BAD_GATEWAY: case SERVICE_UNAVAILABLE: default: callBackError(view, httpException.getMessage()); break; } } else if (e instanceof ConnectException) { callBackError(view, "网络毗连非常,请查抄您的网络状态"); } else if (e instanceof SocketTimeoutException) { callBackError(view, "网络毗连超时,请查抄您的网络状态,稍后重试"); } else if (e instanceof UnknownHostException) { callBackError(view, "网络非常,请查抄您的网络状态"); } else if (e instanceof JSONException || e instanceof ParseException) { callBackError(view, "数据分析错误"); } else if (e instanceof SSLHandshakeException) { callBackError(view, "证书验证失败"); } else if (e instanceof RuntimeException) { callBackError(view, "运行时非常"); } else { callBackError(view, e.toString()); } } catch (Exception e1) { Log.e("mvp[error]", e.getMessage()); } } } /** * {@link #_viewCallBackError} */ private <T> void callBackError(IBaseView<T> view, String message) { view.onCallBack(false, 9000, message, null); Log.e("excce", "UI回调错误信息:" + message); } /** * 返回一个value范例为Object的哈希表 * * @param initSize 大小 * @return Map */ protected Map<String, Object> createMap(int initSize) { return new HashMap<>(initSize); } /** * 返回一个value范例为Integer的哈希表 * * @param initSize 大小 * @return Map */ protected Map<String, Integer> createMapInt(int initSize) { return new HashMap<>(initSize); } /** * 返回一个value范例为String的哈希表 * * @param initSize 大小 * @return Map */ protected Map<String, String> createMapStr(int initSize) { return new HashMap<>(initSize); } /** * 登录状态失效,须要回到登录页 * * @param message message */ protected void onTokenErrorCallBack(String message) { } /** * 动态代理 * * @param <T> 泛型 */ private class MvpViewHandler<T> implements InvocationHandler { private final IBaseView<T> mvpView; MvpViewHandler(IBaseView<T> mvpView) { this.mvpView = mvpView; } @Override @SuppressWarnings("SuspiciousInvocationHandlerImplementation") public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if (isViewAttached(mvpView)) { return method.invoke(this.mvpView, args); } else { Log.d("excci", "页面已关闭,不实行view层方法!"); return null; } } }}4、开始使用
颠末一系列漫长又复杂的封装,终于可以开始使用了,这里就以登录接口和获取用户信息接口为例,展示两个差别模块的使用方法
4.1 根据接口文档编写公共模块的IModelCom
这着实就是各人认识的Service
/** * 公共方法模块 */public interface IModelCom { /** * 登录 * * @param map phone,passWord */ @POST("api/user/login") Observable<CallResult<LoginResponseBean>> login(@Body Map<String, Object> map); /** * 注册 * * @param map phone,code,passWord */ @POST("api/user/register") Observable<CallResult<Void>> register(@Body Map<String, Object> map); /** * 忘记暗码 * * @param map phone,code,newPassWord */ @POST("api/user/forget") Observable<CallResult<Void>> forgetPwd(@Body Map<String, Object> map);}另一个IModelUserCenter的写法差不多的,忽略。
4.2来看看实现类
是否在主线程回调,看本身咯
public class ModelCom extends BaseModel implements IModelCom { private static final class IHolder { static final ModelCom i = new ModelCom(); } public static ModelCom getInstance() { return IHolder.i; } private final IModelCom api; private ModelCom() { api = createService(UrlUtils.IP, IModelCom.class); } @Override public Observable<CallResult<LoginResponseBean>> login(Map<String, Object> map) { return callBackOnUi(api.login(map)); } @Override public Observable<CallResult<Void>> register(Map<String, Object> map) { return callBackOnUi(api.register(map)); } @Override public Observable<CallResult<Void>> forgetPwd(Map<String, Object> map) { return callBackOnUi(api.forgetPwd(map)); }}4.3 左券类
就现在看来,左券类只界说了P层,缘故原由是m层已经是retrofit了,而v层又只有回调参数。
/** * 公共模块左券类 */public interface IContractCom { /** * 公共p层 * {@link com.example.mvpdemo.mvp.presenter.PresenterCom} */ interface IPresenterCom extends IBasePresenter { /** * 登录 * * @param phone 手机号 * @param passWord 暗码 */ void login(String phone, String passWord, IBaseView<LoginResponseBean> view); /** * 注册 * * @param phone 手机号 * @param passWord 暗码 * @param code 验证码 * @param view 回调 */ void register(String phone, String passWord, String code, IBaseView<Void> view); /** * 忘记暗码 * * @param phone 手机号 * @param code 验证码 * @param newPassWord 新暗码 * @param view 回调 */ void forGetPassWord(String phone, String code, String newPassWord, IBaseView<Void> view); }}4.4 P的实现
/** * 公共P */public class PresenterCom extends BasePresenter<IModelCom> implements IContractCom.IPresenterCom { public PresenterCom(Activity activity) { super(activity); } @Override public void login(String phone, String passWord, IBaseView<LoginResponseBean> view) { Map<String, Object> map = createMap(2); map.put("phone", phone); map.put("passWord", passWord); start(module.login(map).map(resp -> { if (isSuccess(resp)) { //假如登录乐成了,则生存token,用户名等信息 Log.i("loginResult", resp.data.token); Log.i("loginResult", resp.data.userName); Log.i("loginResult", String.valueOf(resp.data.roleId)); } return resp; }), view); } @Override public void register(String phone, String passWord, String code, IBaseView<Void> view) { Map<String, Object> map = createMap(3); map.put("phone", phone); map.put("passWord", passWord); map.put("code", code); start(module.register(map), view); } @Override public void forGetPassWord(String phone, String code, String newPassWord, IBaseView<Void> view) { Map<String, Object> map = createMap(3); map.put("phone", phone); map.put("code", code); map.put("newPassWord", newPassWord); start(module.forgetPwd(map), view); } @Override public IModelCom createModel() { return ModelCom.getInstance(); }}4.5 页面的使用
这是登录页的调用方法
public class LoginActivity extends AppCompatActivity { private ActivityLoginBinding view; private IContractCom.IPresenterCom presenterCom; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); view = ActivityLoginBinding.inflate(getLayoutInflater()); setContentView(view.getRoot()); presenterCom = new PresenterCom(this); view.btnLogin.setOnClickListener(v -> { String phone = view.edtPhone.getText().toString(); String pwd = view.edtPwd.getText().toString(); if (TextUtils.isEmpty(phone) || TextUtils.isEmpty(pwd)) { return; } presenterCom.login(phone, pwd, (b, i, s, data) -> { if (b) { Toast.makeText(this, "登录乐成", Toast.LENGTH_SHORT).show(); startActivity(new Intent(this, MainActivity.class)); finish(); } else { Toast.makeText(this, s, Toast.LENGTH_SHORT).show(); } }); }); }}这是首页的调用方法
public class MainActivity extends AppCompatActivity { private ActivityMainBinding view; private IContractUser.IPresenterUser presenterUser; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); view = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(view.getRoot()); //在这种使用方法下,不须要手动解绑 presenterUser = new PresenterUser(this); presenterUser.getUserInfo((b, i, s, data) -> { if (b) { String str = "用户名:" + data.userName + "\n生日:" + data.bir; view.tvMsg.setText(str); } else { Toast.makeText(this, s, Toast.LENGTH_SHORT).show(); } }); }}三、其他说明
3.1 demo下载所在
mvp_demo
3.2 我有一个想法
一样寻常修改手机号、登录和注册,都会用到获取验证码的功能,而这个功能并不须要在修改手机号的模块和登录注册模块都写一次实现逻辑,要是有须要,直接将获取验证码弄成单独的模块大概会更好
public interface IContractPhoneCode { interface IPresenterPhoneCode extends IBasePresenter { void getCode(String phone); }}如在登录页使用的时间,就如许用
public class LoginActivity extends AppCompatActivity { private ActivityLoginBinding view; private IContractCom.IPresenterCom presenterCom; private IContractPhoneCode.IPresenterPhoneCode presenterPhoneCode; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); view = ActivityLoginBinding.inflate(getLayoutInflater()); setContentView(view.getRoot()); presenterCom = new PresenterCom(this); presenterPhoneCode = new PresenterPhoneCode(this); view.btnLogin.setOnClickListener(v -> { String phone = view.edtPhone.getText().toString(); String pwd = view.edtPwd.getText().toString(); if (TextUtils.isEmpty(phone) || TextUtils.isEmpty(pwd)) { return; } presenterCom.login(phone, pwd, (b, i, s, data) -> { if (b) { Toast.makeText(this, "登录乐成", Toast.LENGTH_SHORT).show(); startActivity(new Intent(this, MainActivity.class)); finish(); } else { Toast.makeText(this, s, Toast.LENGTH_SHORT).show(); } }); }); view.btnGetCode.setOnClickListener(v->{ String phone = view.edtPhone.getText().toString(); presenterPhoneCode.getCode(phone,(b,i,s,d)->{ }); }); }}3.3 说明
知识无边无涯,文中如有不敷之处,还望包涵,若能提出您的高见,我将不胜感激。 |