android架構篇mvp+rxjava+retrofit+eventBus

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;
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_login);
       ButterKnife.bind(this);
       presenter=new LoginPresenter(this);
       presenter.start();//初始化控制層
   }

   //實現于view的方法
   @Override
   public 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轉為對象,結構清晰,使用方便.

  • 在APIService中初始化retrofit
 /**
 * 調用后臺的接口,架構網絡層采用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 (待完善)


總結

1.層次分明,各層級之間都不管對方如何實現,只關注結果;
2.在視圖層(Presentation Layer)使用MVP架構,使原本臃腫的Activity(或Fragment)變得簡單,其處理方法都交給了Presenter。
3.易于做測試,只要基于每個模塊單獨做好單元測試就能確保整體的穩定性。
4.易于快速迭代,基于代碼的低耦合,只需在業務邏輯上增加接口,然后在相應的層級分別實現即可,絲毫不影響其他功能。

Blog-link

csdn博客,歡迎大家指正,評閱~謝謝O(∩_∩)O謝謝

git-link

github開源源碼地址,歡迎大家star~,follow,我會不斷完善,您的關注是我前進的動力

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,702評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,615評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,606評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,044評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,826評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,227評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,307評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,447評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,992評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,807評論 3 355
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,001評論 1 370
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,550評論 5 361
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,243評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,667評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,930評論 1 287
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,709評論 3 393
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,996評論 2 374

推薦閱讀更多精彩內容