mvp與mvc得區別
上面這張圖是網上找的,可以明顯得區別MVP和MVC
我們先看一下MVC
- 模型層(model):相當於我們得網絡請求
- 視圖層(view):相當於我們得佈局文件
- 控制層(controller):相當於我們得activity
相當於我們得activity即要和我們得佈局文件打交道,又要和我們得數據層打交道,使得我們得activity就會有相當多得代碼,可讀性降低,而MVP得出現,就剛好彌補了這一點
我們在看一下MVP
- 模型層(model):相當於我們得網絡請求
- 視圖層(view):相當於我們得佈局文件
- 鏈接層(presenter):講model 與 view層進行鏈接
- 不嚴格意義上講,也可以說還有一個controller層,就是我們得activity,只是現在得activity只是用來繼承view,實現view得展示
我們先來實現一個mvp結構
先看我們得M層,就一個接口,用來給activity提供網絡加載出來得數據
public interface MainView extends IBaseView {
//顯示圖片(回調函數)
void showGirlView(List<Girl> girls);
}
再看看model層,這裏我們模仿從網絡上加載圖片
public class MainModel {
public List<Girl> loadData() {
List<Girl> data = new ArrayList<>();
data.add(new Girl(R.drawable.f1, "一星", "****"));
data.add(new Girl(R.drawable.f2, "一星", "****"));
data.add(new Girl(R.drawable.f3, "一星", "****"));
data.add(new Girl(R.drawable.f4, "一星", "****"));
data.add(new Girl(R.drawable.f5, "一星", "****"));
data.add(new Girl(R.drawable.f6, "一星", "****"));
data.add(new Girl(R.drawable.f7, "一星", "****"));
data.add(new Girl(R.drawable.f8, "一星", "****"));
data.add(new Girl(R.drawable.f9, "一星", "****"));
data.add(new Girl(R.drawable.f10, "一星", "****"));
return data;
}
}
再看看presenter層,在這裏,我們通過view得showGirlView方法,將MainModel得到得數據,和MainView中的接口進行綁定
public class MainPresenter<T extends MainView> extends BasePresenter<T> {
MainModel mainModel = new MainModel();
public void loadData(){
iMainView.get().showGirlView(mainModel.loadData());
}
}
然後就是我們得activity層,activity層繼承MainView以後,就可以通過showGirlView方法得到剛纔MainModel 加載得數據
public class MainActivity extends BaseActivity<MainPresenter<MainView>,MainView> implements MainView{
@Override
public void showGirlView(List<Girl> girls) {
//表示層就會把數據填到girls上
listView.setAdapter(new GirlAdapter(this, girls));
}
}
就這樣,我們在mainactivity中就可以得到網絡加載得數據了,這裏我爲了體現MVP得結構,並沒有貼出所有得代碼,完整代碼下載地址demo下載
mvp得改良
我們發現在presenter層裏面,我們將model層得到得數據,再一次得傳遞給了view層,我們可不可以直接將這一次解耦呢
iMainView.get().showGirlView(mainModel.loadData());
下面就是改良得方案,類似RXBus得方式,在model層得到數據,我們就通過單獨得通道,分發出去,在想要這個數據得地方,註冊接受呢
首先我們戴良model得數據加載,將得到得數據,放入通道里面
public class MainModel {
public void loadData() {
RxBusUtils.getInstance().chainProcess(new Function() {
@Override
public Object apply(Object o) throws Exception {
List<Girl> data = new ArrayList<>();
data.add(new Girl(R.drawable.f1, "一星", "****"));
data.add(new Girl(R.drawable.f2, "一星", "****"));
data.add(new Girl(R.drawable.f3, "一星", "****"));
data.add(new Girl(R.drawable.f4, "一星", "****"));
data.add(new Girl(R.drawable.f5, "一星", "****"));
data.add(new Girl(R.drawable.f6, "一星", "****"));
data.add(new Girl(R.drawable.f7, "一星", "****"));
data.add(new Girl(R.drawable.f8, "一星", "****"));
data.add(new Girl(R.drawable.f9, "一星", "****"));
data.add(new Girl(R.drawable.f10, "一星", "****"));
return data;
}
});
}
}
- 如果我們這裏註冊是在presenter裏面
RxBusUtils.getInstance().register(presenter);
就只需要在presenter裏面通過調用這個方法,就可以得到model中得數據,並傳遞給view層
@RegisterRxBusUtils
public void getShowGirlsData(ArrayList<Girl> girls) {
iBaseView.get().showGirlView(girls);
}
- 如果我們將註冊放在activity裏面
RxBusUtils.getInstance().register(MainActiviy.this);
在activity中,就可以直接通過這個方法,得到model中得數據
@RegisterRxBusUtils
public void getShowGirlsData(ArrayList<Girl> girls) {
listView.setAdapter(new GirlAdapter(this, girls));
}
這樣,就可以解耦presenter和view層了
我這裏貼出RxBusUtils 中得方法,提供大家學習
public class RxBusUtils {
private static final String TAG = "RxBusUtils";
//訂閱者集合
private Set<Object> subscribers;
/**
* 註冊
*/
public synchronized void register(Object subscriber){
subscribers.add(subscriber);
}
/**
* 取消註冊
*/
public synchronized void unRegister(Object subscriber){
subscribers.remove(subscriber);
}
//volatile 自帶線程安全(禁止指令重排)
private static volatile RxBusUtils instance;
private RxBusUtils(){
//讀寫分離的集合
subscribers=new CopyOnWriteArraySet<>();
}
public static synchronized RxBusUtils getInstance(){
if (null==instance){
synchronized (RxBusUtils.class){
if (null==instance){
instance = new RxBusUtils();
}
}
}
return instance;
}
/**
* 把處理過程包裝起來
* function:就是用戶的操作
*/
public void chainProcess(Function function){
Observable.just("")
.subscribeOn(Schedulers.io())
.map(function)
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new Consumer() {
@Override
public void accept(Object data) throws Exception {
if (data == null){
return;
}
send(data);
}
});
}
public void send(Object data){
for (Object subscriber : subscribers) {
//掃描註解,將數據發送到註冊的對象標記的位置(一個方法)
//subscriber表示層
callMethodByAnnotation(subscriber,data);
}
}
private void callMethodByAnnotation(Object target, Object data) {
//1.得到presenter中寫的所有的方法
Method[] methodArray = target.getClass().getDeclaredMethods();
//2.如果哪個方法上用了我們寫的註解,就把數據輸入
for (Method method : methodArray) {
Log.d(TAG,"--"+method.getName());
if (null!=method.getAnnotation(RegisterRxBusUtils.class)){
Class<?>[] parameterTypes = method.getParameterTypes();
for (Class<?> parameterType : parameterTypes) {
Log.d(TAG,parameterType.getName());
}
Class paramType = parameterTypes[0];
if (data.getClass().getName().equals(paramType.getName())){
try {
method.invoke(target,new Object[]{data});
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
}
}
上面得方式,是以RXBus通道方式,提供學習使用 修改後得demo下載