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

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 195,980评论 5 462
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,422评论 2 373
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 143,130评论 0 325
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,553评论 1 267
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,408评论 5 358
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,326评论 1 273
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,720评论 3 386
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,373评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,678评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,722评论 2 312
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,486评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,335评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,738评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,009评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,283评论 1 251
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,692评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,893评论 2 335

推荐阅读更多精彩内容