Android之MVP模式
前几天和朋友闲扯聊到了MVP模式,在项目开发中你选择了MVP模式你就最好坚持做下去,因为后期你发现坑越来越大想换回MVC模式就准备推到重来。当然MVP既然能出现那么必然有它的优点。
MVP所对应的意义:M-Model-模型、V-View-视图、P-Presenter-表示器。
先看下整体项目包:
MVP包结构
首先建立一个接口ViewImp:
public interface ViewImp{
//初始化view
public void init(LayoutInflater inflater,ViewGroup container);
//返回view对象
public android.view.View getView();
}
接着我们建立父类BasePresenterActivity<V extends ViewImp>:
public abstract class BasePresenterActivity<V extends ViewImp> extends Activity {
protected V vu;
protected FragmentManager fm;
public EventBus bus;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
//获取到fragmentmanager
fm = getFragmentManager();
//获取到EventBus 主要作用用来解耦
bus = EventBus.getDefault();
//获取子类
vu = (V) getVuClass().newInstance();
//初始化view
vu.init(getLayoutInflater(), null);
setContentView(vu.getView());
//绑定数据
onBindVu();
} catch (Exception e) {
e.printStackTrace();
}
}
//绑定数据
protected void onBindVu() {
}
//返回当前的View的对象
protected abstract Class<MainView> getVuClass();
//可编辑
@Override
protected final void onResume() {
afterOnResume();
super.onResume();
}
public void afterOnResume() { }
// 不可编辑
@Override
protected final void onPause() {
beforeOnPause();
super.onPause();
}
public void beforeOnPause() { }
}
我们接着建立子类MAinActivity:
public class MainActivity extends BasePresenterActivity<MainView> {
// 绑定数据
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
@Override
protected void onBindVu() {
super.onBindVu();
//第一个参数表示替换内容的ID
fm.beginTransaction().replace(vu.getContentId(),ListFragment.newInstance()).commit();
}
@Override
protected Class<MainView> getVuClass() {
return MainView.class;
}
// 处理业务逻辑
@Override
public void beforeOnPause() {
super.beforeOnPause();
bus.unregister(this);
}
// 处理业务逻辑
@Override
public void afterOnResume() {
super.afterOnResume();
bus.registerSticky(this);
}
}
在MainActivity里面看到我们需要传递一个视图MainView:
public class MainView implements ViewImp {
public android.view.View view;
public TextView tv;
private FrameLayout content;
//初始化View
@Override
public void init(LayoutInflater inflater, ViewGroup container) {
//布局就是一个FrameLayout
view= inflater.inflate(R.layout.activity_main,container,false);
content=(FrameLayout) view.findViewById(R.id.content);
}
public int getContentId(){
return content.getId();
}
//返回view
@Override
public android.view.View getView() {
return view;
}
}
从MainActivity里面看到实际我们用ListFragment替换了MainView视图里面的FrameLayout,既然要建立fragment肯定要先建立父类BasePresenterFragment<V extends ViewImp>:
public abstract class BasePresenterFragment<V extends ViewImp> extends Fragment {
public V vu;
// fragment初始化时候调用的方法
@Override
public void onCreate(Bundle savedInstanceState) {
}
// 创建一个view
@Override
public android.view.View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
android.view.View view = null;
try {
//同BasePresenterActivity其实同样获取子类,在子类的视图中初始化
vu = (V) getVuClass().newInstance();
vu.init(inflater, container);
onBindVu();
view = vu.getView();
} catch (Exception e) {
e.printStackTrace();
}
return view;
}
@Override
public void onDestroyView() {
onDestroyVu();
vu=null;
super.onDestroyView();
}
private void onDestroyVu() { }
//绑定view
public void onBindVu() { }
// 获取view对象
public abstract Class<V> getVuClass();
}
接着看子类ListFragment:
public class ListFragment extends BasePresenterFragment<ListView>{
ListViewAdapter adapter= new ListViewAdapter();
ViewCallback<Integer> selectCallback= new ViewCallback<Integer>() {
@Override
public void execute(Integer result) {
}
};
@Override
public void onBindVu() {
super.onBindVu();
vu.setListAdapter(adapter);
vu.selectCallback(selectCallback);
}
@Override
public Class<ListView> getVuClass() {
return ListView.class;
}
// 实例化当前对象
public static ListFragment newInstance(){
return new ListFragment();
}
}
通过ListFragment发现视图在ListView中,而在fragment中我们进行的是逻辑处理。
ListView:
public class ListView implements ViewImp {
private android.widget.ListView listview;
private android.view.View view;
public ViewCallback<Integer> selectCallback;
@Override
public void init(LayoutInflater inflater, ViewGroup container) {
view = inflater.inflate(R.layout.list, container, false);
listview=(android.widget.ListView) view.findViewById(R.id.listview);
listview.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, android.view.View view, int position, long id) {
if(selectCallback!=null){
selectCallback.execute(position);
}
}
});
}
@Override
public android.view.View getView() {
return null;
}
public void setListAdapter(ListViewAdapter adapter) {
listview.setAdapter(adapter);
}
public void selectCallback(ViewCallback<Integer> selectCallback) {
}
}
在这个地方我们建立了一个接口 ViewCallback<T>,这样我们就可以将listview的点击事件逻辑放在fragment中进行,将view与逻辑分开。
public interface ViewCallback<T> {
public void execute(T result);
}
于此同时我们建立了适配器ListAdapter,为了方便处理,我们同样建立了BasePresenterAdapter<V extends ViewImp>:
public abstract class BasePresenterAdapter<V extends ViewImp> extends BaseAdapter {
public V vu;
private V vuClass;
@Override
public android.view.View getView(int position, android.view.View convertView, ViewGroup parent) {
if(convertView==null){
//获取填充布局
LayoutInflater inflater = (LayoutInflater)parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
try {
vu= (V) getVuClass().newInstance();
//初始化view
vu.init(inflater,parent);
//获取当前view
convertView= vu.getView();
convertView.setTag(vu);
} catch (Exception e) {
e.printStackTrace();
}
}else{
vu= (V) convertView.getTag();
}
if(convertView!=null){
//绑定数据
onBindListItemVu(position);
}
return convertView;
}
public abstract void onBindListItemVu(int position);
public abstract Class<V> getVuClass();
}
因为所有的getview可以抽取出来放在父类,子类ListViewAdapter:
public class ListViewAdapter extends BasePresenterAdapter <ListItemView>{
List<String> titles= new ArrayList<String>(Content.VALUE_MAP.keySet());
@Override
public void onBindListItemVu(int position) {
String title = titles.get(position);
vu.setTitle(title);
}
@Override
public Class<ListItemView> getVuClass() {
return ListItemView.class;
}
@Override
public int getCount() {
return titles.size();
}
@Override
public Object getItem(int position) {
return titles.get(position);
}
public String getTitle(int postion) {
return (String) getItem(postion);
}
@Override
public long getItemId(int position) {
return position;
}
}
实际在这个Listview中item的布局我简单放了有一个textview,ListItemView:
public class ListItemView implements ViewImp {
public TextView textview;
public android.view.View view;
@Override
public void init(LayoutInflater inflater, ViewGroup container) {
view = inflater.inflate(R.layout.ipsum_list_item, container, false);
textview = (TextView) view.findViewById(R.id.text);
}
@Override
public android.view.View getView() {
return view;
}
public void setTitle(String title) {
textview.setText(title);
}
}
里面数据我偷懒就放在bean里面 请别打我。。。
public class Content {
public String title;
public String body;
public Content(String title, String body) {
this.title = title;
this.body = body;
}
//所有数据
public static Map<String,Content> VALUE_MAP=new HashMap<String,Content>();
static {
VALUE_MAP.put("敲敲demo",new Content("真的敲敲demo","自己敲demo"));
}
}
刚开始用的时候可能比较麻烦,当你父类完成以后后期的复用还是挺给力的。
源码地址 https://github.com/Xu-xiaobei/MVP_demo