標籤:
android架構篇mvp+rxjava+retrofit+eventBus
高層不應該知道低層的細節,應該是面向抽象的編程。業務的實現交給實現的介面的類。高層只負責調用。
首先,要介紹一下一個項目中好架構的好處:好的軟體設計必須能夠協助開發人員發展和擴充解決方案,保持代碼清晰健壯,並且可擴充,易於維護,而不必每件事都重寫代碼。面對軟體存在的問題,必須遵守SOLID原則(物件導向五大原則),不要過度工程化,儘可能降低架構中模組的依賴性。
之前的一段時間,學習了一些新的技術,並把自己關注的技術整合了一下,是的,相似的技術有很多,自己擇優選擇,將它們的思想和技術應用到了自己的搭建的項目架構中.
限於自己能力水平有限,自己搭建的項目可能還有些不足,歡迎大家指正批評,讓自己的想法和設計思想走向正軌.O(∩_∩)O謝謝~
在架構中
1.項目整體架構: 利用google-clean-architecture的思想 來負責項目的整體MVP架構.
MVP是模型(Model)、視圖(View)、主持人(Presenter)的縮寫,分別代表項目中3個不同的模組。我以登入狀態例子,進行說明.
這裡每個業務首先要有一個管理介面Contract,在這裡面有三個介面來面向介面編程, (Model),(View),(Presenter). 將三個介面放在一起便於管理.
/** * 登入關聯結口類 * * Created by ccj on 2016/7/7. */public interface LoginContract { interface View extends BaseView { void showProgress(); void hideProgress(); void showError(String error); void navigateToMain(); void navigateToRegister(); } interface Presenter extends BasePresenter { void login(String username, String password); void onDestroy(); } interface Model{ void saveUserInfo(User user); void saveLoginState(Boolean isLogin); void saveRememberPass(User user); }}
模型(Model):實現 implements LoginContract.Model 負責處理資料的載入或者儲存,比如從網路或本機資料庫擷取資料等;這裡的login 涉及到的商務邏輯比較少請求網路 採用了rxjava +retroft+gsons 相當於 model層. 如果處理的出具多,就採用此model ,就像圖片儲存顯示等等.
視圖(View):採用介面的方式,讓activity實現該介面,介面中有關於視圖的方法,例如”initVIew()”,”showDialog()”,”hideDialog()”等等, 負責介面資料的展示,與使用者進行互動;
public class LoginActivity extends BaseActivity implements LoginContract.View {//省略bufferknife 註解private LoginPresenter presenter;@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); ButterKnife.bind(this); presenter=new LoginPresenter(this); presenter.start();//初始化控制層}//實現於view的方法@Overridepublic void navigateToMain() { Intent intent =new Intent(getBaseContext(),MainActivity.class); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); startActivity(intent);}
- 主持人(Presenter):持有 view和model的對象,操作兩者的方法.相當於協調者,是模型與視圖之間的橋樑,將模型與視圖分離開來,對view 和model 進行調度操作。
/** * login的presenter層 進行對view 和 model 的控制, * Created by ccj on 2016/7/7. */public class LoginPresenter implements LoginContract.Presenter { private LoginContract.View loginView; public LoginPresenter(LoginContract.View loginView) { this.loginView = loginView; } @Override public void login(String username, String password) { loginView.showProgress(); Observable<User> userObservable = APIService.userLogin(username, password); userObservable.subscribeOn(Schedulers.io()) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Subscriber<User>() { @Override public void onCompleted() { loginView.hideProgress(); } @Override public void onError(Throwable e) { TLog.log(e.getMessage().toString()); loginView.hideProgress(); loginView.showError(e.getMessage().toString()); } @Override public void onNext(User getIpInfoResponse) { TLog.log(getIpInfoResponse.toString()); loginView.navigateToMain(); } }); } @Override public void start() { }
2.網路訪問: 採用rxjava+retrofit+gson進行網路訪問,並輕鬆的將json轉為對象,結構清晰,使用方便.
/** * 調用背景介面,架構網路層採用Retroft+Rxjava+gson * Created by ccj on 2016/7/1. * */public class APIService { private static final String TAG = "APIService"; public static final String URL_HOST ="http://123.234.82.23" ;//伺服器連接埠 /** * 基礎地址 * 初始化 retroft */ private static final Retrofit sRetrofit = new Retrofit.Builder() .baseUrl(URL_HOST) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 使用RxJava作為回調適配器 .build(); private static final RetrofitRequest apiManager = sRetrofit.create(RetrofitRequest.class); /** * 登入,返回,我這邊用的是json格式的post,大家可以進行選擇 * @param city * @return */ public static Observable<User> userLogin(String format, String city) { HashMap<String,String> hashMap =new HashMap<>(); hashMap.put("UserPhone", format); hashMap.put("UserPassWord", city); TLog.log(hashMap.toString()); Observable<User> ss = apiManager.userLogin(hashMap); return ss; } /**********************仿照上面的方法,進行請求資料****************************/
- 用retrofit訪問 返回observable的對象
public interface RetrofitRequest { boolean isTest=true; //是否在測試環境下 //發布之前更改 String BASE_URL_TEST = "/flyapptest/";//測試伺服器 String BASE_URL_OFFICAL = "/flyapp/";//正式伺服器 String BASE_URL = isTest?BASE_URL_TEST:BASE_URL_OFFICAL;//發行伺服器 /** * 登入返回(json post) * @param body * @return */ @Headers( "Content-Type: application/json" ) @POST(BASE_URL+"Login.ashx/") Observable<User> userLogin(@Body HashMap<String, String> body);
3.非同步處理: 採用rxjava響應式架構進行優雅的非同步處理,簡化代碼邏輯,並且很好的解決記憶體流失 問題.(相關模組在TakePhoto業務中)
/** * rxjava 進行非同步作業 eventBus進行時間傳遞 * @param data */ @Override public void savePhoto(final Intent data) { TLog.log("savePhoto", "data-->" + data.getData().toString()); Log.e("Tlog-->", "data-->" + data.getData().toString()); saveObservable = Observable.fromCallable(new Callable<String>() { @Override public String call() throws Exception {//通知調用 並返回string return savePic(data);//此方法在io線程中調用 並返回 } }); saveSubscription = saveObservable .subscribeOn(Schedulers.io())//observable在調度中的IO線程中進行調度進行 .observeOn(AndroidSchedulers.mainThread())//在主線程中進行觀察 .subscribe(new Observer<String>() {//訂閱觀察者 @Override public void onCompleted() { Log.e("Tlog-->", "onCompleted-->"); } @Override public void onError(Throwable e) { Log.e("Tlog-->", "Throwable-->" + e.getMessage().toString()); EventBus.getDefault().post(new EventUtils.ObjectEvent(e.getMessage().toString())); } @Override public void onNext(String s) {//帶參數的下一步,在此就是當 Log.e("Tlog-->", "s-->" + s); EventBus.getDefault().post(new EventUtils.ObjectEvent(bitmap)); } }); }
4.事件訂閱: 採用EventBus作為事件匯流排,進行線程間,組件之間的通訊.
/** * 事件匯流排 用於組件或線程通訊,可替代回調,廣播等 * Created by ccj on 2016/4/14. */public class EventUtils { /** * object類型(即傳統的所有類型,都可以強轉進行傳遞事件) */ public static class ObjectEvent{ private Object object; public ObjectEvent(Object object) { // TODO Auto-generated constructor stub this.object = object; } public Object getMsg(){ return object; } }}
5.代碼分包: 根據業務區分進行分包,便於對代碼進行管理 .
6. 工具類: TDeviceUtils裝置狀態的工具類,,SeriliazebleUtils 序列化工具類,SharepreferenceUtils儲存工具類,
相關請參考代碼
7.app棧管理: 基於baseActivity,很好的釋放記憶體,管理記憶體.
相關請參考代碼
待後期完成
異常捕獲(待完善)
測試架構Espresso/JUnit/Mockito/Robolectric (待完善)
gradle相關構建編譯
總結
1.層次分明,各層級之間都不管對方如何?,只關注結果;
2.在視圖層(Presentation Layer)使用MVP架構,使原本臃腫的Activity(或Fragment)變得簡單,其處理方法都交給了Presenter。
3.易於做測試,只要基於每個模組單獨做好單元測試就能確保整體的穩定性。
4.易於快速迭代,基於代碼的低耦合,只需在商務邏輯上增加介面,然後在相應的層級分別實現即可,絲毫不影響其他功能。
code-link
—— [ github開源源碼地址,歡迎大家star~,follow,我會不斷完善,您的關注是我前進的動力 ]
[android架構篇]mvp+rxjava+retrofit+eventBus