Android之MVP模式

前幾天和朋友閑扯聊到了MVP模式威始,在項目開發(fā)中你選擇了MVP模式你就最好堅持做下去逼庞,因為后期你發(fā)現(xiàn)坑越來越大想換回MVC模式就準備推到重來。當然MVP既然能出現(xiàn)那么必然有它的優(yōu)點。
MVP所對應(yīng)的意義:M-Model-模型十电、V-View-視圖、P-Presenter-表示器。
先看下整體項目包:


MVP包結(jié)構(gòu)

首先建立一個接口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());  
      //綁定數(shù)據(jù)       
   onBindVu();     
   } catch (Exception e) {     
   e.printStackTrace();    
  }   
 }  
  //綁定數(shù)據(jù) 
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> {    
  // 綁定數(shù)據(jù)    
  @TargetApi(Build.VERSION_CODES.HONEYCOMB) 
  @Override 
  protected void onBindVu() {   
 super.onBindVu();   
 //第一個參數(shù)表示替換內(nèi)容的ID 
fm.beginTransaction().replace(vu.getContentId(),ListFragment.newInstance()).commit();  
  }
 @Override   
protected Class<MainView> getVuClass() {     
 return MainView.class; 
    }
// 處理業(yè)務(wù)邏輯     
@Override 
 public void beforeOnPause() {   
 super.beforeOnPause();     
 bus.unregister(this);  
  }   
// 處理業(yè)務(wù)邏輯   
 @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初始化時候調(diào)用的方法    
  @Override   
  public void onCreate(Bundle savedInstanceState) {  
  }   
  //  創(chuàng)建一個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發(fā)現(xiàn)視圖在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){ 
       //綁定數(shù)據(jù) 
       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);
  }
}

里面數(shù)據(jù)我偷懶就放在bean里面 請別打我。抵蚊。施绎。

public class Content {
public String title;
public String body;
public Content(String title, String body) {
    this.title = title;
    this.body = body;
}
//所有數(shù)據(jù)
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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末谷醉,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子冈闭,更是在濱河造成了極大的恐慌俱尼,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拒秘,死亡現(xiàn)場離奇詭異号显,居然都是意外死亡,警方通過查閱死者的電腦和手機躺酒,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門押蚤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人羹应,你說我怎么就攤上這事揽碘。” “怎么了园匹?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵雳刺,是天一觀的道長。 經(jīng)常有香客問我裸违,道長掖桦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任供汛,我火速辦了婚禮枪汪,結(jié)果婚禮上涌穆,老公的妹妹穿的比我還像新娘。我一直安慰自己雀久,他們只是感情好宿稀,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著赖捌,像睡著了一般祝沸。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上越庇,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天罩锐,我揣著相機與錄音,去河邊找鬼悦荒。 笑死唯欣,一個胖子當著我的面吹牛嘹吨,可吹牛的內(nèi)容都是我干的搬味。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蟀拷,長吁一口氣:“原來是場噩夢啊……” “哼碰纬!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起问芬,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤悦析,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后此衅,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體强戴,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年挡鞍,在試婚紗的時候發(fā)現(xiàn)自己被綠了骑歹。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡墨微,死狀恐怖道媚,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情翘县,我是刑警寧澤最域,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站锈麸,受9級特大地震影響镀脂,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜忘伞,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一薄翅、第九天 我趴在偏房一處隱蔽的房頂上張望钞馁。 院中可真熱鬧,春花似錦匿刮、人聲如沸僧凰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽训措。三九已至,卻和暖如春光羞,著一層夾襖步出監(jiān)牢的瞬間绩鸣,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工纱兑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留呀闻,地道東北人。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓潜慎,卻偏偏與公主長得像捡多,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子铐炫,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,098評論 25 707
  • 本文適用讀者:已經(jīng)熟練掌握Android編程但沒學過MVP模式的程序員垒手。 說起MVP模式,我也看過好多相關(guān)文章了倒信。...
    范范范范范范閱讀 1,127評論 2 33
  • 前言 MVC科贬、MVP、MVVM一直以來都是Android應(yīng)用常見的架構(gòu)模式鳖悠,都是為了抽離出UI邏輯和業(yè)務(wù)邏輯榜掌。但是...
    希格斯子閱讀 1,173評論 0 1
  • 一 What Daily Scrum? Daily Scrum即每日站會,一個方面匯報之前的工作進度和遇到的問題乘综,...
    caosiwei閱讀 130評論 0 0
  • 紫霞說:“不論明不明白瘾带,我已經(jīng)不是神仙了鼠哥。我只明白一件事,愛一個人是那么的痛苦看政∑涌遥” 至尊寶回到五百年前尋找白晶晶,...
    婪苼閱讀 2,277評論 1 3