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