protected abstract void getData();
@Override
protected void onDestroy() {
super.onDestroy();
…
if (null != mPresenter) {
mPresenter.detachView();
}
}
}
BaseActivity设置两个泛型——V和P,明显地,分别代表对应的View和Presenter。
其持有一个BasePresenter,在onCreated方法中,使用createPresenter方法返回对应的BasePresenter的子类,我们就可以使用了。
这里注意一下view和presenter的处理:在onCreated中创建Presenter对象,但其内部的view软引用还是空;在onResume中关联view,此时presenter已经持有view的软引用;当然,还需要在onDestroy中取消关联。
至于其他的封装就不再介绍了,相信大家肯定还有更优的封装方法。
2.2 BaseFragment
public abstract class BaseFragment<V, T extends BasePresenter> extends Fragment {
public String TAG = getClass().getSimpleName() + “”;
private static final String STATE_SAVE_IS_HIDDEN = “STATE_SAVE_IS_HIDDEN”;
protected T mPresenter;
//定义一个View用来保存Fragment创建的时候使用打气筒工具进行的布局获取对象的存储
protected View view;
/**
- 当Fragment进行创建的时候执行的方法
*/
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mPresenter = createPresenter();//创建presenter
}
@Override
public void onSaveInstanceState(Bundle outState) {
outState.putBoolean(STATE_SAVE_IS_HIDDEN, isHidden());
}
/**
- 这个方法是关于Fragment完成创建的过程中,进行界面填充的方法,该方法返回的是一个view对象
- 在这个对象中封装的就是Fragment对应的布局
*/
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
view = initFragmentView(inflater);
return view;
}
/**
- 这个方法当onCreateView方法中的view创建完成之后,执行
- 在inflate完成view的创建之后,可以将对应view中的各个控件进行查找findViewById
*/
@Override
public void onViewCreated(View view, Bundle savedInstanceState) {
initFragmentChildView(view);
}
/**
- 这个方法是在Fragment完成创建操作之后,进行数据填充操作的时候执行的方法
*/
@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
initFragmentData(savedInstanceState);
}
/**
- 完成打气筒操作
*/
protected abstract View initFragmentView(LayoutInflater inflater);
/**
- 进行findViewById的操作
- @param view 打气筒生成的View对象
*/
protected abstract void initFragmentChildView(View view);
/**
- 网络数据填充的操作
- @param savedInstanceState
*/
protected abstract void initFragmentData(Bundle savedInstanceState);
/**
- 创建Presenter对象
*/
protected abstract T createPresenter();
@Override
public void onResume() {
super.onResume();
if (null != mPresenter) {
mPresenter.attachView((V) this);
}
}
@Override
public void onDestroy() {
super.onDestroy();
if (null != mPresenter) {
mPresenter.detachView();
}
}
}
BaseFragment与BaseA类似就不再累赘。
3、Contract契约类
契约,顾名思义,规范定义,定义功能和模板。
在契约类中定义View的接口,Model的接口。因为Model将数据返给Presenter是使用回调方式,所以还需要再契约类中定义对应的回调。
具体看示例吧。
实战
这里我们以登录功能模块为例:
1、契约类
/**
- Description:
- Created by jia on 2017/12/20.
- 人之所以能,是相信能
*/
public class LoginContract {
public interface LoginView{
void onCheckFormatSuccess();
void onCheckFormatFail(String info);
void onLoginSuccess(Login login);
void onLoginFail(String errorInfo);
}
public interface LoginModel{
void login(String name,String password,LoginCallBack callBack);
}
public interface LoginCallBack{
void onSuccess(Login login);
void onFail(String errorInfo);
}
}
这里定义了登录页面的view接口、model接口和对应的回调。
在view中,只定义与UI展示的相关方法,如检查账号密码格式成功(失败)、登录成功(失败)等。
model负责数据请求,所以在接口中只定义了登录的方法。
回调定义了登录成功还是失败的方法。
2、Model实现类
/**
- Description: 登录 Model实现类
- Created by jia on 2017/12/20.
- 人之所以能,是相信能
*/
public class LoginModelImpl implements LoginContract.LoginModel {
/**
- 登录方法
- @param name
- @param password
- @param callBack
*/
@Override
public void login(String name, String password, final LoginContract.LoginCallBack callBack) {
LoginNetUtils.getInstance().login(name, password, new BaseSubscriber() {
@Override
public void onSuccess(Login login) {
callBack.onSuccess(login);
}
@Override
public void onFail(String info) {
callBack.onFail(info);
}
});
}
}
创建Model实现类,重写其登录方法既可,将登录接口交给回调。
3、Presenter
/**
- Description: 登录主持类
- Created by jia on 2017/12/20.
- 人之所以能,是相信能
*/
public class LoginPresenter extends BasePresenter<LoginContract.LoginView> {
private LoginModelImpl model;
public LoginPresenter() {
model = new LoginModelImpl();
}
/**
- 检查格式
- @param name
- @param password
*/
public void checkFormat(String name, String password) {
if (TextUtils.isEmpty(name)) {
getView().onCheckFormatFail(“请输入用户名”);
} else if (TextUtils.isEmpty(password)) {
getView().onCheckFormatFail(“请输入密码”);
} else if (password.length() < 6 || password.length() > 18) {
getView().onCheckFormatFail(“密码格式不正确”);
} else {
getView().onCheckFormatSuccess();
login(name, password);
}
}
/**
- 登录
- @param name
- @param password
*/
public void login(String name, String password) {
model.login(name, password, new LoginContract.LoginCallBack() {
@Override
public void onSuccess(Login login) {
getView().onLoginSuccess(login);
}
@Override
public void onFail(String errorInfo) {
getView().onLoginFail(errorInfo);
}
});
}
}
LoginPresenter集成BasePresenter,传入LoginView最为泛型T。
内部持有Model实现类对象。
创建两个方法,一个是检查格式,一个是登录。两个方法就是业务的处理。
如登录方法,登录返回后,在回调中得到数据,也可以再进行一些逻辑判断,将结果交给view的对应的方法。
注意这里使用getView()方法就可以,因为在父类中getView方法直接返回的对应的view实例。
4、View
/**
- 登录界面
*/
public class LoginActivity extends BaseActivity<LoginContract.LoginView, LoginPresenter>
implements LoginContract.LoginView, View.OnClickListener {
…
@Override
protected void initActivityView(Bundle savedInstanceState) {
setContentView(R.layout.activity_login);
}
@Override
protected void findViewById() {
…
}
@Override
protected LoginPresenter createPresenter() {
return new LoginPresenter();
}
@Override
protected void getData() {
}
@Override
public void onCheckFormatSuccess() {
loading.show();
}
@Override
public void onCheckFormatFail(String info) {
RxToast.error(mContext, info).show();
}
@Override
public void onLoginSuccess(Login login) {
…
}
@Override
public void onLoginFail(String errorInfo) {
…
}
@Override
public void onClick(View view) {
…
}
…
}
这里的LoginActivity就是登录功能模块的view,其集成BaseActivity,传入view和presenter泛型。
实现LoginView接口,重写接口定义好的UI方法。
在createPresenter方法中创建LoginPresenter对象并返回。这样,就可以使用mPresenter直接操作逻辑了。
写在最后
在技术领域内,没有任何一门课程可以让你学完后一劳永逸,再好的课程也只能是“师傅领进门,修行靠个人”。“学无止境”这句话,在任何技术领域,都不只是良好的习惯,更是程序员和工程师们不被时代淘汰、获得更好机会和发展的必要前提。
如果你觉得自己学习效率低,缺乏正确的指导,可以一起学习交流!
加入我们吧!群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。
35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。
《Android学习笔记总结+移动架构视频+大厂面试真题+项目实战源码》,点击传送门,即可获取!