Upload
-wu
View
1.199
Download
0
Embed Size (px)
Citation preview
基於 Flow & Path 的 MVP 架構
⽞玄武
功能需求:導覽/註冊/登⼊入/⾸首⾴頁
Sample Code: https://github.com/tuvvut/FlowPathSample
IntroductionActivity
RegisterActivity
LoginActivity
HomeActivity
MainActivity
功能需求:導覽/註冊/登⼊入/⾸首⾴頁
功能需求:導覽/註冊/登⼊入/⾸首⾴頁
MainActivity
RegisterFragment
LoginFragment
HomeFragment
IntroductionFragment
此圖由 Steve Pomeroy 完成分享此圖需要 CC BY-SA 4.0 許可
需要⽤用那麼多個 Activity 嗎?
Fragment 複雜的⽣生命週期導致多少問題?
public class LoginFragment extends Fragment implements View.OnClickListener { EditText account; TextView textView; Button button; private static int showTimeCount = 0; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.login, container, false); button = (Button) v.findViewById(R.id.button); button.setOnClickListener(this); textView = ((TextView) v.findViewById(R.id.textView)); account = ((EditText) v.findViewById(R.id.account)); showTimeCount++; showMessage(); return v; } private void showMessage() { String message = "此⾴頁⾯面顯⽰示次數:" + showTimeCount; button.setText(message); textView.setText(message); account.setText(message); Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show(); }
public class LoginFragment extends Fragment implements View.OnClickListener { EditText account; TextView textView; Button button; private static int showTimeCount = 0; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View v = inflater.inflate(R.layout.login, container, false); button = (Button) v.findViewById(R.id.button); button.setOnClickListener(this); textView = ((TextView) v.findViewById(R.id.textView)); account = ((EditText) v.findViewById(R.id.account)); showTimeCount++; showMessage(); //在這裡呼叫的話,會造成 EditText 無法更新⽂文字 return v; } private void showMessage() { String message = "此⾴頁⾯面顯⽰示次數:" + showTimeCount; button.setText(message); textView.setText(message); account.setText(message); Toast.makeText(getActivity(), message, Toast.LENGTH_SHORT).show(); } @Override public void onViewStateRestored(Bundle savedInstanceState) { //showMessage(); 必須在這裡呼叫,才能更新 EditText 的⽂文字 super.onViewStateRestored(savedInstanceState); }
Sample Code:https://github.com/tuvvut/edittext_bug
Square:從今天開始拋棄 Fragment 吧!http://www.devtf.cn/?p=598
功能需求:導覽/註冊/登⼊入/⾸首⾴頁
MainActivity
RegisterPage
LoginPage
HomePage
IntroductionPage
Flow is a small library that helps with describing an app as a collection of moderately independent screens.
Flow allows you to enumerate to your app's UI states and navigate between them.
Flow
Flow is a small library that helps with describing an app as a collection of moderately independent screens.
Flow allows you to enumerate to your app's UI states and navigate between them.
Flow
Flow 現在的版本只有 0.1X,要⽤用在正式的專案上要三思
Flow 的⽂文件少得可憐...只能從官⽅方 Sample Code 去了解 Flow 是怎麼運作的
官⽅方 Sample Code 包含 Dagger、Butterknife 的 Code,不熟悉的⼈人會看得很痛苦
dependencies { compile 'com.squareup.flow:flow:0.12' compile ‘com.squareup.flow:flow-path:0.12’ compile 'com.google.code.gson:gson:2.3' }
前置作業Sample Code:
https://github.com/tuvvut/FlowPathSample
Flow 切換⾴頁⾯面的⽅方式//回前⼀一個⾴頁⾯面 Flow.get(context).goBack();
Flow 切換⾴頁⾯面的⽅方式//回前⼀一個⾴頁⾯面 Flow.get(context).goBack();
//到下⼀一個⾴頁⾯面(例如:進⼊入登⼊入畫⾯面) Flow.get(context).set(new LoginPath());
Flow 切換⾴頁⾯面的⽅方式//回前⼀一個⾴頁⾯面 Flow.get(context).goBack();
//到下⼀一個⾴頁⾯面(例如:進⼊入登⼊入畫⾯面) Flow.get(context).set(new LoginPath());
//清空之前的⾴頁⾯面並到下⼀一⾴頁(例如:登⼊入成功,不希望按 Back 會再看到登⼊入畫⾯面) History history = History.single(new HomePath(name)); Flow.get(context).setHistory(history, Flow.Direction.FORWARD);
Flow 切換⾴頁⾯面的⽅方式//回前⼀一個⾴頁⾯面 Flow.get(context).goBack();
//到下⼀一個⾴頁⾯面(例如:進⼊入登⼊入畫⾯面) Flow.get(context).set(new LoginPath());
//清空之前的⾴頁⾯面並到下⼀一⾴頁(例如:登⼊入成功,不希望按 Back 會再看到登⼊入畫⾯面) History history = History.single(new HomePath(name)); Flow.get(context).setHistory(history, Flow.Direction.FORWARD);
//清空之前的⾴頁⾯面並返回(例如:登出,不希望按 Back 會再看到登出以前畫⾯面) History history = History.single(new IntroductionPath()); Flow.get(context).setHistory(history, Flow.Direction.BACKWARD);
基本架構Activity
Path
Path
Path
Path(POJO)Custom View
Presenter
JAVA
XML
…
以 Home 為例Activity
IntroductionPath
RegisterPath
LoginPath
HomePath
切換到 Home ⾴頁⾯面 Flow.get(context).set(new HomePath(name));
以 Home 為例Activity
IntroductionPath
RegisterPath
LoginPath
HomePathCustom View
page_home.xml
切換到 Home ⾴頁⾯面 Flow.get(context).set(new HomePath(name));
@Layout(R.layout.page_home) public class HomePath extends Path { private String userName = “"; public HomePath(String userName) { this.userName = userName; }}
以 Home 為例Activity
IntroductionPath
RegisterPath
LoginPath
HomePathCustom View
HomePage.java
page_home.xml
切換到 Home ⾴頁⾯面 Flow.get(context).set(new HomePath(name));
<com.tuvvut.flowpathsample.page.Home.HomePage xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> . . . . .</com.tuvvut.flowpathsample.page.Home.HomePage>
@Layout(R.layout.page_home) public class HomePath extends Path { private String userName = “"; public HomePath(String userName) { this.userName = userName; }}
以 Home 為例Activity
IntroductionPath
RegisterPath
LoginPath
HomePathCustom View
HomePresenter
HomePage.java
page_home.xml
public class HomePage extends RelativeLayout { private HomePresenter presenter; public HomePage(Context context, AttributeSet attrs) { super(context, attrs); presenter = new HomePresenter(context, this); }}
切換到 Home ⾴頁⾯面 Flow.get(context).set(new HomePath(name));
<com.tuvvut.flowpathsample.page.Home.HomePage xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> . . . . .</com.tuvvut.flowpathsample.page.Home.HomePage>
@Layout(R.layout.page_home) public class HomePath extends Path { private String userName = “"; public HomePath(String userName) { this.userName = userName; }}
以 Home 為例Activity
IntroductionPath
RegisterPath
LoginPath
HomePathCustom View
HomePresenter
HomePage.java
page_home.xml
public class HomePage extends RelativeLayout { private HomePresenter presenter; public HomePage(Context context, AttributeSet attrs) { super(context, attrs); presenter = new HomePresenter(context, this); }}
切換到 Home ⾴頁⾯面 Flow.get(context).set(new HomePath(name));
<com.tuvvut.flowpathsample.page.Home.HomePage xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> . . . . .</com.tuvvut.flowpathsample.page.Home.HomePage>
@Layout(R.layout.page_home) public class HomePath extends Path { private String userName = “"; public HomePath(String userName) { this.userName = userName; }}
public class HomePresenter { private Context context; private HomePage page; public HomePresenter(Context context, HomePage page) { this.context = context; this.page = page; }}
MVP
View Presenter Model
MVP
View Presenter Model
各部分彼此獨⽴立 View 變得很乾淨
Presenter 很好做單元測試
如何重複利⽤用 Presenters?
Sample Code: https://github.com/tuvvut/FlowPathSample/tree/feature/add_HomePage2
• Square:從今天開始拋棄 Fragment 吧!http://www.devtf.cn/?p=598
• Square 開源庫 Flow 和 Mortar 的介紹https://goo.gl/lA8NRz
• Flowhttps://github.com/square/flow
參考資料