上一篇文章写的是mvp的简单实现,这一篇是写mvp的简单封装,另外说一下,文章内容都是我个人的理解然后输出,有些东西可能说的不太准确,请注意甄别, 或者留言交流。当然, 本人也会尽最大能力写的正确,但是。。。请多包含,谢谢。
开始封装
上来我就直给,先搞BaseView
public interface BaseView {
void showToast(String str);
}
先定义一个BaseView,然后里面写一个toast的方法给子类重写,暂时就先写这一个方法吧。然后重点来了,因为项目主要用的fragment,所以我这边用BaseFragment,activity同理;
public abstract class BaseFragment<T extends BasePresenter> extends Fragment implements BaseView{
protected T mPresenter;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mPresenter = createPresenter();
if (mPresenter!=null){
mPresenter.attachView(this);
}
return super.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onDestroyView() {
if (mPresenter!=null){
mPresenter.detach();
}
super.onDestroyView();
}
protected abstract T createPresenter();
@Override
public void showToast(String str) {
Toast.makeText(getContext(), str, Toast.LENGTH_SHORT).show();
}
}
1,直接加上个abstract来修饰, 变成抽象类, 这样就不能通过new的方式来实现BaseFragment,保证他是一个纯粹的基类。
2,实现了BaseView接口, 然后重写了showToast方法,子类就不需要多次重复的写这个方法了。
3,这里有一个 抽象方法 createPresenter,返回的是T,这个是泛型,T extends BasePresenter 就是BasePresenter的子类,需要在子类实现,我们在onCreateView里面调用后拿到对象, 然后通过mPresenter.attachView(this);绑定了presenter和view,先不要着急问attachView是哪里来的,马上解答。
上面搞完了BaseFragment,然后来看BasePresenter
public abstract class BasePresenter<T extends BaseView> {
protected T view;
public void attachView(T view){
this.view = view;
}
public void detach(){
view = null;
}
protected boolean isAttached(){
return view != null;
}
}
1,依然是上来就写个abstract,不让new这个对象。
2,现在发现,这里有三个方法,attachView,detach,isAttached,就是上面第三个的答案,现在V-P已经连在一起了,p可以知道V有没有销毁回收
基类写完了,然而并没有写model的,因为没啥好写的,model都不太一样,没有BaseModel。
开始实现
先看MainPresenter
public class MainPresenter extends BasePresenter<MainView> {
public void getData(){
MainModel.getList(new MainContract.CallBack() {
@Override
public void modelCallBack(String... str) {
if (isAttached()){
view.upDateMsg(str[0]);
view.showToast(str[0]);
}
}
});
}
}
首先mainPresenter提供了一个getData,然后调用了model的获取数据的方法, 同时传了一个callback,在回调里面判断view没有销毁的话调用view的方法把数据传到view层。
MainFragment:
public class MainFragment extends BaseFragment<MainPresenter> implements MainView{
Button button;
TextView textView;
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.main_fragment,container,false);
mPresenter = createPresenter();
mPresenter.attachView(this);
view.findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mPresenter.getData();
}
});
return view;
}
@Override
protected MainPresenter createPresenter() {
return new MainPresenter();
}
@Override
public void showToast(final String str) {
getActivity().runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(getContext(), str, Toast.LENGTH_SHORT).show();
}
});
}
@Override
public void upDateMsg(String text) {
Log.e("---", text);
}
}
1,在这里实现了抽象方法createPresenter。
2,然后重写了showToast 因为这里其实是子线程, 在这里toast是会报错的。
3,你会发现多了一个方法 upDateMsg,其实是因为实现了一个MainView接口才多的,其实也可以把这个方法放在BaseView里面,但是总会有一些方法不通用, 放在这里是为了举例,下面是MianView的代码:
public interface MainView extends BaseView {
void upDateMsg(String text);
}
存在的问题
上篇文章写到,如果在获取文章的时候页面销毁了,那么获取到数据回传然后更新时,发现view==null,此时就会发生空指针异常。已经在上面的代码里面解决了,如果没发现, 再读一下吧。
这篇文章就写到这里, 下一篇开始引入第三方框架,解决线程切换之类的问题。