34.Android MVC框架 - Robotlegs4Androird
- Android MVC框架 - Robotlegs4Androird
- Android 耦合的MVC
- Robotlegs4Android MVC
- Robotlegs4Android Gradle
- Robotlegs4Android Github
- Robotlegs4Android Model
- Robotlegs4Android View
- Robotlegs4Androird Event
- Robotlegs4Android Controller
- Robotlegs4Android Context
- Robotlegs4Android Application
- Event View to Controller
- Event Model to Controller
- Event Model to View
- Event Controller to View
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 Gradle
dependencies {
compile 'com.camnter.robotlegs4android:robotlegs4android:0.8'
}
Robotlegs4Android Github
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);
Login 的execute()
方法能拿到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
UserModel 的login(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
UserModel 的login(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);
}