編輯:關於Android編程
首先自問自答:
首先要知道為什麼要選擇開發框架?目的如下:
代碼可讀維護性好方便測試 框架的核心思想:解耦 分層:縱向上的解耦模塊化:橫向上的解耦橫向的模塊化:對大家來可能並不陌生,在一個項目建立項目文件夾的時候就會遇到這個問題,通常的做法是將相同功能的模塊放到同一個目錄下,更復雜的,可以通過插件化來實現功能的分離與加載。縱向的分層,不同的項目可能就有不同的分法,並且隨著項目的復雜度變大,層次可能越來越多
根據自己具體項目而定,如果業務簡單的項目,用MVC模式就可以了,不管是什麼開發框架,都是為了更好的提高工作效率,是手段,方法,不是目的,不要為了設計而設計,否則浪費時間,精力,得不償失。
為什麼要思考這問題?因為時間短暫,想要做的事情很多,必須學會取捨,才能更好的做好事情。
我有個原則:
最重要的事情,只有一件,要麼不做,要麼就做得最好
好處:
可以做其他,自己認為更重要的事情
壞處:
思維方面:對於一些基於MVP模式優秀項目,但是看不懂啊,閱讀大神優秀思想的作品,
無法享受思維上的樂趣,怎麼能阻礙我們成為大神的前進道路呢?不可原諒,beat it !
工作方面:如果項目業務很復雜,使用MVC模式,項目開發效率,管理,代碼可讀性低,測試和維護時間長,工作效率低
所以從否定角度,證明學習MVP模式是重要,是必須的,於是花時間,專門學習,研究MVP模式,運用到工作項目中,提高工作效率
1)如何認識MVP模式?(觀察現象)
回顧MVC模式
比較MVC模式和MVP模式的區別,通過比較區別,顯出MVP模式的特點,優勢
2)如何使用MVP模式?(使用方法)
通過例子分析
當將架構改為MVP以後,Presenter的出現,將Actvity視為View層,Presenter負責完成View層與Model層的交互。現在是這樣的:
View 對應於Activity,負責顯示數據,View的繪制以及與用戶交互Model 業務邏輯和實體模型Presenter 負責完成View於Model間的交互,處理著程序各種邏輯的分發,收到View層UI上的反饋命令、定時命令、系統命令等指令後分發處理邏輯交由Model層做具體的業務操作。如圖所示:
有圖觀察可知:MCV模式與MVP模式最明顯的區別就是,
MVC中是允許Model和View進行交互的,而MVP中很明顯,Model與View之間的交互由Presenter完成。還有一點就是Presenter與View之間的交互是通過接口的
1. 降低耦合度,實現了Model和View真正的完全分離,可以修改View而不影響Modle
2. 模塊職責劃分明顯,層次清晰
3. 隱藏數據
4. Presenter可以復用,一個Presenter可以用於多個View,而不需要更改Presenter的邏輯(當然是在View的改動不影響業務邏輯的前提下)
5. 利於測試驅動開發。
6. View可以進行組件化。在MVP當中,View不依賴Model。這樣就可以讓View從特定的業務場景中脫離出來,可以說View可以做到對業務完全無知。它只需要提供一系列接口提供給上層操作。這樣就可以做到高度可復用的View組件。
7. 代碼靈活性
1. Presenter中除了應用邏輯以外,還有大量的View->Model,Model->View的手動同步邏輯,造成Presenter比較笨重,維護起來會比較困難。
2. 由於對視圖的渲染放在了Presenter中,所以視圖和Presenter的交互會過於頻繁,view裡的行為太過復雜,應對復雜場景勢必造成代碼行為膨脹
3. 如果Presenter過多地渲染了視圖,往往會使得它與特定的視圖的聯系過於緊密。一旦視圖需要變更,那麼Presenter也需要變更了。
4. 額外的代碼復雜度及學習成本
例子:實現效果:簡單登陸界面功能,輸入姓名,密碼,然後點擊登陸按鍵,提示登陸結果,點擊清除按鍵,清除輸入內容
1)分析Model數據模型,實體類有什麼屬性和行為。
比如:這個例子中,登陸功能,需要一個用戶模型User
package com.example.juphome.mvpdemo.Login.bean; /** * Created by Juphome on 2017/1/15. */ public class User { private String username ; private String password ; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }
2)定義操作具體業務類的回調接口:OnLoginListener,用於回調監聽登陸結果狀態
package com.example.juphome.mvpdemo.Login.biz; import com.example.juphome.mvpdemo.Login.bean.User; /** * Created by Juphome on 2017/1/15. */ public interface OnLoginListener { void loginSuccess(User user); void loginFailed(); }定義操作業務類的抽象接口:IUserBiz
package com.example.juphome.mvpdemo.Login.biz; import com.example.juphome.mvpdemo.Login.bean.User; /** * Created by Juphome on 2017/1/15. */ public interface OnLoginListener { void loginSuccess(User user); void loginFailed(); }實現操作業務類的抽象接口:UserBiz
package com.example.juphome.mvpdemo.Login.biz; import com.example.juphome.mvpdemo.Login.bean.User; /** * Created by Juphome on 2017/1/15. */ public class UserBiz implements IUserBiz{ @Override public void login(final String username, final String password, final OnLoginListener loginListener) { //模擬子線程耗時操作 new Thread() { @Override public void run() { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } //模擬登錄成功 if ("zhy".equals(username) && "123".equals(password)) { User user = new User(); user.setUsername(username); user.setPassword(password); loginListener.loginSuccess(user); } else { loginListener.loginFailed(); } } }.start(); } }
定義契約類(接口)
使用契約類來統一管理view與presenter的所有的接口,這種方式使得view與presenter中有哪些功能,一目了然,維護起來也很方便。
Presenter是用作Model和View之間交互的橋梁,那麼應該有什麼方法呢?
其實也是主要看該功能有什麼操作,比如本例,兩個操作:login和clear。
package com.example.juphome.mvpdemo.Login.biz; import com.example.juphome.mvpdemo.Login.bean.User; /** * Created by Juphome on 2017/1/15. */ public interface UserBizContract { interface IUserLoginView { String getUserName(); String getPassword(); void clearUserName(); void clearPassword(); void showLoading(); void hideLoading(); void toMainActivity(User user); void showFailedError(); } interface Presenter{ void login(); void clear(); } }
package com.example.juphome.mvpdemo.Login.presenter; import android.os.Handler; import com.example.juphome.mvpdemo.Login.bean.User; import com.example.juphome.mvpdemo.Login.biz.IUserBiz; import com.example.juphome.mvpdemo.Login.biz.OnLoginListener; import com.example.juphome.mvpdemo.Login.biz.UserBiz; import com.example.juphome.mvpdemo.Login.biz.UserBizContract; /** * Created by Juphome on 2017/1/15. */ public class UserLoginPresenter implements UserBizContract.Presenter { private IUserBiz userBiz; private UserBizContract.IUserLoginView userLoginView; private Handler mHandler = new Handler(); public UserLoginPresenter(UserBizContract.IUserLoginView userLoginView) { this.userLoginView = userLoginView; this.userBiz = new UserBiz(); } @Override public void login() { userLoginView.showLoading(); userBiz.login(userLoginView.getUserName(), userLoginView.getPassword(), new OnLoginListener() { @Override public void loginSuccess(final User user) { //需要在UI線程執行 mHandler.post(new Runnable() { @Override public void run() { userLoginView.toMainActivity(user); userLoginView.hideLoading(); } }); } @Override public void loginFailed() { //需要在UI線程執行 mHandler.post(new Runnable() { @Override public void run() { userLoginView.showFailedError(); userLoginView.hideLoading(); } }); } }); } @Override public void clear() { userLoginView.clearUserName(); userLoginView.clearPassword(); } }
最後讓Model-View-Presenter動態聯系起來
讓Activity實現View的接口IUserLoginView,MVP中的View其實就是Activity,調用Presenter,處理業務操作,Presenter處理過程中,通知Activity界面友好提示,顯示緩沖數據圖標,Presenter處理業務操作完成後,回調通知Activity結果狀態,失敗或成功的數據
package com.example.juphome.mvpdemo.Login.view; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.ProgressBar; import android.widget.Toast; import com.example.juphome.mvpdemo.Login.bean.User; import com.example.juphome.mvpdemo.Login.biz.UserBizContract; import com.example.juphome.mvpdemo.Login.presenter.UserLoginPresenter; import com.example.juphome.mvpdemo.R; /** * Created by Juphome on 2017/1/15. */ public class UserLoginActivity extends Activity implements UserBizContract.IUserLoginView { private EditText mEtUsername, mEtPassword; private Button mBtnLogin, mBtnClear; private ProgressBar mPbLoading; private UserLoginPresenter mUserLoginPresenter = new UserLoginPresenter(this); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_user_login); initViews(); } private void initViews() { mEtUsername = (EditText) findViewById(R.id.id_et_username); mEtPassword = (EditText) findViewById(R.id.id_et_password); mBtnClear = (Button) findViewById(R.id.id_btn_clear); mBtnLogin = (Button) findViewById(R.id.id_btn_login); mPbLoading = (ProgressBar) findViewById(R.id.id_pb_loading); mBtnLogin.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mUserLoginPresenter.login(); } }); mBtnClear.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mUserLoginPresenter.clear(); } }); } @Override public String getUserName() { return mEtUsername.getText().toString(); } @Override public String getPassword() { return mEtPassword.getText().toString(); } @Override public void clearUserName() { mEtUsername.setText(""); } @Override public void clearPassword() { mEtPassword.setText(""); } @Override public void showLoading() { mPbLoading.setVisibility(View.VISIBLE); } @Override public void hideLoading() { mPbLoading.setVisibility(View.GONE); } @Override public void toMainActivity(User user) { Toast.makeText(this, user.getUsername() + " login success , to MainActivity", Toast.LENGTH_SHORT).show(); } @Override public void showFailedError() { Toast.makeText(this, "login failed", Toast.LENGTH_SHORT).show(); } }
使用MVP模式的步驟:
定義mode層的實體類,操作業務類的接口操作業務類完成的結果狀態監聽接口定義view的接口。定義Presenter接口實現定義好的View接口和Presenter接口讓MVP動起來讓Acivity實現view接口,在Activity中創建Presenter引用對象,用Presenter對象,操作Model的業務邏輯處理,Model層處理完成後,通過業務監聽回調接口,告訴Presenter處理業務的結果如何,最後Persenter通過VIew接口,讓Activity進行頁面數據更新
前言新版本ShareSDK的分享和短信驗證,按官網的文檔,都需要添加一個標簽,而分享和短息驗證的這個標簽內容都一樣。會沖突。解決辦法:分享用舊版本,短信驗證用新版本。後面
一、效果圖先來看看效果圖吧~~二、實現原理方案1、自定義ViewGroup-XCDanmuView,繼承RelativeLayout來實現,當然也可以繼承其他三大布局類哈
管理Activity(Fragment、dialogFragment)的生命周期需要在build.gradle中加入compile 'com.trello:rxl
在android中提供了一種異步回調機制Handler,使用它,我們可以在完成一個很長時間的任務後做出相應的通知 handler基本使用: 在主線