34.Android MVC框架 - Robotlegs4Androird

34.Android MVC框架 - Robotlegs4Androird


Android 耦合的MVC

說到Android上的MVC,還真的不好區分。很多時候都是這樣的,View層和Controller層總是傻傻分不清楚

Model層顯而易見的是各種bean(實體),配上 gson 或者 fastjson 解析網絡請求回來的json,生成各種實例。

但是,在View層的 Activity 或 Fragment 上,雖然有View層的理念,避免不了很多Controller層的業務過度耦合在View層。

總結得出,View層(Activity、Fragment)除了自身的生命週期回調方法(onCreate、onStart … 等)外,還摻雜了各種Controller業務(直接操作Model、DB操作 … 等)

反正就是,各種亂七八糟的東西都放在Activity 或 Fragment,各種難看,各種耦合。

在這種情況下,衍生出了 MVP 和 MVVM 。現在主流的還是MVP,MVVM目前在Android上還不成熟,還處於測試階段。


Robotlegs4Android MVC

這是Robotlegs4Android 的 MVC 流程圖。

  • EventDispatcher 完成各層之間的通信。
  • Mediator 代理 View 層的業務,View層只顯示簡單的生命週期回調方法。
  • Command 作爲 Controller 層,對 View 傳過來的業務進行相應處理。
  • Actor 作爲 Model 層,爲 Command 提供 DB 的請求(SQLite 或 網絡請求)。

robotlegs4android_mvc


Robotlegs4Android Gradle

dependencies {
    compile 'com.camnter.robotlegs4android:robotlegs4android:0.8'
}

Robotlegs4Android Github

Robotlegs4Android


Robotlegs4Android Model

extends Actor

定義一個Robotlegs4Android Model對象,只需要繼承 Actor 即可。

UserModel

public class UserModel extends Actor {

    public void login(String name,String password) {

        // TODO Do you want to network requests

    }

    public boolean logout(){

        // TODO Do you want to network requests

        return true;
    }


}

User

public class User implements Serializable {

    public String name;

    public String sign;

}

Robotlegs4Android View

  • Robotlegs4Android Activity
  • Robotlegs4Android Fragment

Robotlegs4Android Activity

  • 如果你這個Activity不需要Fragment。 extends RobotlegsActivity
  • 如果你這個Activity需要Fragment。 extends RobotlegsFragmentActivity

MainActivity (看起來真的很簡單)

public class MainActivity extends RobotlegsFragmentActivity {

    /**
     * Please set the fragment layout id
     * 請設置Fragment的佈局Id
     *
     * @return
     */
    @Override
    public int getLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }

}

MainActivityMediator(這裏處理Activity要做的事情)

public class MainActivityMediator extends Mediator {

    private static final String TAG = "MainActivityMediator";

    private MainActivity activity;

    private TabLayout tabLayout;
    private ViewPager viewPager;

    /**
     * {@inheritDoc}
     * {@linkplain IMediator #onRegister}
     */
    @Override
    public void onRegister() {
        this.activity = (MainActivity) this.getViewComponent();
        this.initViews();
        this.initData();
    }

    private void initViews() {
        this.tabLayout = (TabLayout) this.activity.findViewById(R.id.tab_layout_tl);
        this.viewPager = (ViewPager) this.activity.findViewById(R.id.view_pager_vp);
    }

    private void initData() {
        String[] tabTitles = {"ONE", "TWO", "THR", "FOU"};
        Fragment[] fragments = {
                TabLayoutFirstFragment.getInstance(),
                TabLayoutSecondFragment.getInstance(),
                TabLayoutThirdFragment.getInstance(),
                TabLayoutFourthFragment.getInstance()
        };
        MainActivityAdapter adapter = new MainActivityAdapter(this.activity.getSupportFragmentManager(), fragments, tabTitles);
        this.viewPager.setAdapter(adapter);
        this.tabLayout.setupWithViewPager(this.viewPager);
    }

}

Robotlegs4Android Fragment

extends RobotlegsFragment

TabLayoutFirstFragment(看起來真的很簡單)

public class TabLayoutFirstFragment extends RobotlegsFragment {

    private static TabLayoutFirstFragment instance;

    private TabLayoutFirstFragment() {
    }

    public static TabLayoutFirstFragment getInstance() {
        if (instance == null) instance = new TabLayoutFirstFragment();
        return instance;
    }

    /**
     * Please set the fragment layout id
     * 請設置Fragment的佈局Id
     *
     * @return
     */
    @Override
    public int getLayoutId() {
        return R.layout.tablayout_first_fragment;
    }

}

TabLayoutFirstFragmentMediator(這裏處理Fragment要做的事情)

public class TabLayoutFirstFragmentMediator extends Mediator implements View.OnClickListener {

    public TabLayoutFirstFragment fragment;
    public FragmentActivity activity;

    private Button firstBT;
    private TextView firstTV;
    private ImageView firstIV;
    private TextView controllerTV;


    /**
     * {@inheritDoc}
     * {@linkplain IMediator #onRegister}
     */
    @Override
    public void onRegister() {
        this.fragment = (TabLayoutFirstFragment) this.getViewComponent();

        this.activity = this.fragment.getActivity();
        this.initViews();
        this.initData();
    }

    private void initViews() {
        this.firstBT = (Button) this.fragment.self.findViewById(R.id.first_bt);
        this.firstTV = (TextView) this.fragment.self.findViewById(R.id.first_tv);
        this.firstIV = (ImageView) this.fragment.self.findViewById(R.id.first_iv);
        this.controllerTV = (TextView) this.fragment.self.findViewById(R.id.first_controller_tv);
    }

    private void initData() {
        this.firstTV.setText("The ONE created by robotlegs4android frame");
    }

    /**
     * Called when a view has been clicked.
     *
     * @param v The view that was clicked.
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.first_bt: {
            }
        }
    }

}

Robotlegs4Androird Event

extends com.camnter.robotlegs4android.base.Event

爲了各個層之間的通信,定義一個Event類型。

LoginEvent

public class LoginEvent extends Event {

    public static final String USER_LOGIN = "user_login";
    public static final String USER_LOGOUT = "user_logout";

    public static final String USER_LOGIN_SUCCESS_FROM_MODEL_TO_CONTROLLER = "user_login_success_from_model_to_controller";
    public static final String USER_LOGIN_SUCCESS_FROM_MODEL_TO_VIEW = "user_login_success_from_model_to_view";
    public static final String USER_LOGIN_SUCCESS_FROM_CONTROLLER_TO_VIEW = "user_login_success_from_controller_to_view";

    public String name;
    public String password;

    public User user;

    public LoginEvent(String type) {
        super(type);
    }

}

Robotlegs4Android Controller

extends Command

有了通訊,自然也要有Controller去處理,發向Controller的事件。

Login

public class Login extends Command {

    private static final String TAG = "Login";

    @Inject
    public UserModel userModel;

    @Inject
    public LoginEvent event;

    /**
     * TODO - The Command subclass must inherit the execute method
     * 備忘錄 - Command子類必須繼承execute方法
     */
    @Override
    public void execute() {
        switch (event.getType()) {
            case LoginEvent.USER_LOGIN: {
                userModel.login(event.name, event.password);
                break;
            }
            case LoginEvent.USER_LOGOUT: {
                userModel.logout();
                break;
            }
            case LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_CONTROLLER: {
                break;
            }
        }
    }


!!!!!! Robotlegs4Android Context

extends com.camnter.robotlegs4android.mvcs.Context

必須定義一個com.camnter.robotlegs4android.mvcs.Context

  • 1.爲了配置View和對應Mediator。
  • 2.爲了單例注入Model(Actor)。
  • 3.爲了配置傳入Controller(Command)的事件。

MainContext

public class MainContext extends Context {

    public MainContext(Object contextView, Boolean autoStartup) {
        super(contextView, autoStartup);
    }

    /**
     * set your mvc relation
     * 設置你的mvc關係
     * <p/>
     * Add the view map
     * Link the View and View the corresponding Mediator
     * 添加view映射
     * 將View 和 View 對應的 Mediator 聯繫起來
     * <p/>
     * Injection as an singleton, instantiate the singleton
     * 注入實例,實例化單例
     * <p/>
     * Add Event (Event) with the connection of the Command
     * 添加事件(Event)與Command的聯繫
     */
    @Override
    public void setMvcRelation() {

        /*
         * view映射
         * 將View 和 View 對應的 Mediator 聯繫起來
         * Add the view map
         * Link the View and View the corresponding Mediator
         */
        this.getMediatorMap().mapView(MainActivity.class, MainActivityMediator.class, null, true, true);
        this.getMediatorMap().mapView(TabLayoutFirstFragment.class, TabLayoutFirstFragmentMediator.class, null, true, true);
        this.getMediatorMap().mapView(TabLayoutSecondFragment.class, TabLayoutSecondFragmentMediator.class, null, true, true);
        this.getMediatorMap().mapView(TabLayoutThirdFragment.class, TabLayoutThirdFragmentMediator.class, null, true, true);
        this.getMediatorMap().mapView(TabLayoutFourthFragment.class, TabLayoutFourthFragmentMediator.class, null, true, true);

        /*
         * 注入實現 實例化單例
         * Injection as an singleton, instantiate the singleton
         */
        this.getInjector().mapSingleton(UserModel.class, "");

        /*
         * 添加事件與Command的聯繫
         * Add Event (Event) with the connection of the Command
         */
        this.getCommandMap().mapEvent(LoginEvent.USER_LOGIN, Login.class,
                null, false);
        this.getCommandMap().mapEvent(LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_CONTROLLER, Login.class, null, false);

    }

}

!!!!!! Robotlegs4Android Application

extends RobotlegsApplication

必須定義一個Robotlegs4Android Application去初始化,對應的Robotlegs4Android Context

MainApplication

public class MainApplication extends RobotlegsApplication {

    private static MainApplication ourInstance = new MainApplication();

    public static MainApplication getInstance() {
        return ourInstance;
    }


    /**
     * Please write your custom robotlegs4android context
     * 請填寫你自定義的robotlegs4android context
     * TODO After write your custom robotlegs4android context, please don't call this method
     * TODO 填寫完你自定義的robotlegs4android context後,請不要調用此方法
     *
     * @return
     */
    @Override
    protected Context getMvcContextInstance() {
        return new MainContext(this, true);
    }

    /**
     * Called when the application is starting, before any activity, service,
     * or receiver objects (excluding content providers) have been created.
     * Implementations should be as quick as possible (for example using
     * lazy initialization of state) since the time spent in this function
     * directly impacts the performance of starting the first activity,
     * service, or receiver in a process.
     * If you override this method, be sure to call super.onCreate().
     */
    @Override
    public void onCreate() {
        super.onCreate();
        if (ourInstance == null) ourInstance = this;
    }

}

AndroidManifest.xml

    <application
        android:name="com.camnter.robotlegs4android.test.application.MainApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".view.activity.MainActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

Event View to Controller

TabLayoutFirstFragmentMediator 發送一個LoginEvent.USER_LOGIN的LoginEvent。

    /**
     * Called when a view has been clicked.
     *
     * @param v The view that was clicked.
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.first_bt: {
                /*
                 * you can send a your custom event from Model layer to Controller layer,and the
                 * frame will search the event configuration from your custom context
                 * 你可以發送一個你自定義的事件從Model層到Controller層,並且框架會去你自定義的context搜索
                 * 這個事件的配置
                 */
                LoginEvent loginEvent = new LoginEvent(LoginEvent.USER_LOGIN);
                loginEvent.name = "CaMnter";
                loginEvent.password = "Save you from anything";
                this.dispatch(loginEvent);
            }
        }
    }

MainContext 設置了LoginEvent.USER_LOGIN事件的去向的Controller。

        this.getCommandMap().mapEvent(LoginEvent.USER_LOGIN, Login.class,
                null, false);

Loginexecute()方法能拿到LoginEvent.USER_LOGIN事件。

    @Inject
    public LoginEvent event;


    /**
     * TODO - The Command subclass must inherit the execute method
     * 備忘錄 - Command子類必須繼承execute方法
     */
    @Override
    public void execute() {
        switch (event.getType()) {
            case LoginEvent.USER_LOGIN: {
                userModel.login(event.name, event.password);
                break;
            }
            case LoginEvent.USER_LOGOUT: {
                userModel.logout();
                break;
            }
            case LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_CONTROLLER: {
                Log.i(TAG, "This Login Controller know the user login success");

                /*
                 * send an USER_LOGIN_SUCCESS_FROM_CONTROLLER_TO_VIEW type of event to View layer
                 * 發送一個USER_LOGIN_SUCCESS_FROM_CONTROLLER_TO_VIEW類型的事件到View層
                 */
                this.dispatch(new LoginEvent(LoginEvent.USER_LOGIN_SUCCESS_FROM_CONTROLLER_TO_VIEW));
                break;
            }
        }
    }

Event Model to Controller

UserModellogin(String name,String password)方法發送一個LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_CONTROLLER的LoginEvent。

    public void login(String name,String password) {

        // TODO Do you want to network requests

        User user = new User();
        user.name = "CaMnter";
        user.sign = "Save you from anything";

        /*
         * you can send a your custom event from Model layer to Controller layer
         * 你可以發送一個你自定義的事件從Model層到Controller層
         */
        this.dispatch(new LoginEvent(LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_CONTROLLER));
    }

Event Model to View

UserModellogin(String name,String password)方法再發送一個LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_VIEW的LoginEvent。

    public void login(String name,String password) {

        // TODO Do you want to network requests

        User user = new User();
        user.name = "CaMnter";
        user.sign = "Save you from anything";

        /*
         * you can send a your custom event from Model layer to View layer
         * 你可以發送一個你自定義的事件從Model層到View層
         */
        LoginEvent loginEvent = new LoginEvent(LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_VIEW);
        loginEvent.user = user;
        this.dispatch(loginEvent);
        /*
         * you can send a your custom event from Model layer to Controller layer
         * 你可以發送一個你自定義的事件從Model層到Controller層
         */
        this.dispatch(new LoginEvent(LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_CONTROLLER));
    }

Mediator.getEventMap().mapListener(IEventDispatcher dispatcher, String type,IListener listener, Class<?> eventClass, Boolean useCapture,int priority, Boolean useWeakReference)
TabLayoutFirstFragmentMediator 添加對LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_VIEW類型的LoginEvent的監聽。

     */
    @Override
    public void onRegister() {
        this.fragment = (TabLayoutFirstFragment) this.getViewComponent();

        this.activity = this.fragment.getActivity();
        this.initViews();
        this.initData();
        this.initListeners();
    }

    private void initViews() {
        this.firstBT = (Button) this.fragment.self.findViewById(R.id.first_bt);
        this.firstTV = (TextView) this.fragment.self.findViewById(R.id.first_tv);
        this.firstIV = (ImageView) this.fragment.self.findViewById(R.id.first_iv);
        this.controllerTV = (TextView) this.fragment.self.findViewById(R.id.first_controller_tv);
    }

    private void initData() {
        this.firstTV.setText("The ONE created by robotlegs4android frame");
    }

    private void initListeners() {
        this.firstBT.setOnClickListener(this);
        /*
         * listening your custom event(such as listening to an USER_LOGIN_SUCCESS type of LoginEvent)
         * listening from Model layer to View layer in here
         * 監聽你的自定義事件(例如監聽一個USER_LOGIN_SUCCESS_FROM_MODEL_TO_CONTROLLER_AND_VIEW類型的LoginEvent)
         * 在這裏監聽從Model層到View層
         */
        this.getEventMap().mapListener(this.getEventDispatcher(), LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_VIEW, new Listener() {
                    /**
                     * {@inheritDoc}
                     * <p/>
                     * {@linkplain IListener #onHandle}
                     *
                     * @param event
                     */
                    @Override
                    public void onHandle(Event event) {
                        if (event instanceof LoginEvent) {
                            TabLayoutFirstFragmentMediator.this.firstIV.setVisibility(View.VISIBLE);
                        }
                    }
                }, null,
                false, 0, true);
    }

Event Controller to View

Login 發送一個LoginEvent.USER_LOGIN_SUCCESS_FROM_CONTROLLER_TO_VIEW類型的LoginEvent。

    /**
     * TODO - The Command subclass must inherit the execute method
     * 備忘錄 - Command子類必須繼承execute方法
     */
    @Override
    public void execute() {
        switch (event.getType()) {
            case LoginEvent.USER_LOGIN: {
                userModel.login(event.name, event.password);
                break;
            }
            case LoginEvent.USER_LOGOUT: {
                userModel.logout();
                break;
            }
            case LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_CONTROLLER: {
                Log.i(TAG, "This Login Controller know the user login success");

                /*
                 * send an USER_LOGIN_SUCCESS_FROM_CONTROLLER_TO_VIEW type of event to View layer
                 * 發送一個USER_LOGIN_SUCCESS_FROM_CONTROLLER_TO_VIEW類型的事件到View層
                 */
                this.dispatch(new LoginEvent(LoginEvent.USER_LOGIN_SUCCESS_FROM_CONTROLLER_TO_VIEW));
                break;
            }
        }
    }

Mediator.getEventMap().mapListener(IEventDispatcher dispatcher, String type,IListener listener, Class<?> eventClass, Boolean useCapture,int priority, Boolean useWeakReference)
TabLayoutFirstFragmentMediator 再添加一個對LoginEvent.USER_LOGIN_SUCCESS_FROM_CONTROLLER_TO_VIEW類型的LoginEvent的監聽。

    /**
     * {@inheritDoc}
     * {@linkplain IMediator #onRegister}
     */
    @Override
    public void onRegister() {
        this.fragment = (TabLayoutFirstFragment) this.getViewComponent();

        this.activity = this.fragment.getActivity();
        this.initViews();
        this.initData();
        this.initListeners();
    }

    private void initViews() {
        this.firstBT = (Button) this.fragment.self.findViewById(R.id.first_bt);
        this.firstTV = (TextView) this.fragment.self.findViewById(R.id.first_tv);
        this.firstIV = (ImageView) this.fragment.self.findViewById(R.id.first_iv);
        this.controllerTV = (TextView) this.fragment.self.findViewById(R.id.first_controller_tv);
    }

    private void initData() {
        this.firstTV.setText("The ONE created by robotlegs4android frame");
    }

    private void initListeners() {
        this.firstBT.setOnClickListener(this);

        /*
         * listening your custom event(such as listening to an USER_LOGIN_SUCCESS type of LoginEvent)
         * listening from Model layer to View layer in here
         * 監聽你的自定義事件(例如監聽一個USER_LOGIN_SUCCESS_FROM_MODEL_TO_CONTROLLER_AND_VIEW類型的LoginEvent)
         * 在這裏監聽從Model層到View層
         */
        this.getEventMap().mapListener(this.getEventDispatcher(), LoginEvent.USER_LOGIN_SUCCESS_FROM_MODEL_TO_VIEW, new Listener() {
                    /**
                     * {@inheritDoc}
                     * <p/>
                     * {@linkplain IListener #onHandle}
                     *
                     * @param event
                     */
                    @Override
                    public void onHandle(Event event) {
                        if (event instanceof LoginEvent) {
                            TabLayoutFirstFragmentMediator.this.firstIV.setVisibility(View.VISIBLE);
                        }
                    }
                }, null,
                false, 0, true);

        /*
         * listening your custom event(such as listening to an USER_LOGIN_SUCCESS type of LoginEvent)
         * listening from Controller layer to View layer in here
         * 監聽你的自定義事件(例如監聽一個USER_LOGIN_SUCCESS_FROM_CONTROLLER_TO_VIEW類型的LoginEvent)
         * 在這裏監聽從Controller層到View層
         */
        this.getEventMap().mapListener(this.getEventDispatcher(), LoginEvent.USER_LOGIN_SUCCESS_FROM_CONTROLLER_TO_VIEW, new Listener() {
            /**
             * {@inheritDoc}
             * <p/>
             * {@linkplain IListener #onHandle}
             *
             * @param event
             */
            @Override
            public void onHandle(Event event) {
                if (event instanceof LoginEvent) {
                    TabLayoutFirstFragmentMediator.this.controllerTV.setVisibility(View.VISIBLE);
                }
            }
        }, null, false, 0, true);

    }

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