【android學習】MVP學習

mvp與mvc得區別

上面這張圖是網上找的,可以明顯得區別MVP和MVC

我們先看一下MVC

  1. 模型層(model):相當於我們得網絡請求
  2. 視圖層(view):相當於我們得佈局文件
  3. 控制層(controller):相當於我們得activity

相當於我們得activity即要和我們得佈局文件打交道,又要和我們得數據層打交道,使得我們得activity就會有相當多得代碼,可讀性降低,而MVP得出現,就剛好彌補了這一點

我們在看一下MVP

  1. 模型層(model):相當於我們得網絡請求
  2. 視圖層(view):相當於我們得佈局文件
  3. 鏈接層(presenter):講model 與 view層進行鏈接
  4. 不嚴格意義上講,也可以說還有一個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下載

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章