android架構(gòu)篇mvp+rxjava+retrofit+eventBus

android架構(gòu)篇

mvp+rxjava+retrofit+eventBus


高層不應(yīng)該知道低層的細節(jié)距境,應(yīng)該是面向抽象的編程拥坛。業(yè)務(wù)的實現(xiàn)交給實現(xiàn)的接口的類恼布。高層只負責(zé)調(diào)用耳贬。


首先,要介紹一下一個項目中好架構(gòu)的好處:好的軟件設(shè)計必須能夠幫助開發(fā)者發(fā)展和擴充解決方案攒射,保持代碼清晰健壯醋旦,并且可擴展,易于維護会放,而不必每件事都重寫代碼饲齐。面對軟件存在的問題,必須遵守SOLID原則(面向?qū)ο笪宕笤瓌t)咧最,不要過度工程化捂人,盡可能降低框架中模塊的依賴性。


之前的一段時間,學(xué)習(xí)了一些新的技術(shù),并把自己關(guān)注的技術(shù)整合了一下,是的,相似的技術(shù)有很多,自己擇優(yōu)選擇,將它們的思想和技術(shù)應(yīng)用到了自己的搭建的項目框架中.
限于自己能力水平有限,自己搭建的項目可能還有些不足,歡迎大家指正批評,讓自己的想法和設(shè)計思想走向正軌.O(∩_∩)O謝謝~

在框架中

1.項目整體框架: 利用google-clean-architecture的思想 來負責(zé)項目的整體MVP架構(gòu).**

  • MVP是模型(Model)矢沿、視圖(View)滥搭、主持人(Presenter)的縮寫,分別代表項目中3個不同的模塊捣鲸。我以登錄為例子,進行說明.
這里寫圖片描述

這里每個業(yè)務(wù)首先要有一個管理接口Contract,在這里面有三個接口來面向接口編程, (Model),(View),(Presenter). 將三個接口放在一起便于管理.

這里寫圖片描述
   /**
 * 登錄關(guān)聯(lián)接口類
 *
 * 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):實現(xiàn) implements LoginContract.Model 負責(zé)處理數(shù)據(jù)的加載或者存儲瑟匆,比如從網(wǎng)絡(luò)或本地數(shù)據(jù)庫獲取數(shù)據(jù)等;這里的login 涉及到的業(yè)務(wù)邏輯比較少請求網(wǎng)絡(luò) 采用了rxjava +retroft+gsons 相當(dāng)于 model層. 如果處理的出具多,就采用此model ,就像圖片保存顯示等等.

  • 視圖(View):采用接口的方式,讓activity實現(xiàn)該接口,接口中有關(guān)于視圖的方法,例如”initVIew()”,”showDialog()”,”hideDialog()”等等, 負責(zé)界面數(shù)據(jù)的展示栽惶,與用戶進行交互愁溜;

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();//初始化控制層
   }

   //實現(xiàn)于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的對象,操作兩者的方法.相當(dāng)于協(xié)調(diào)者无午,是模型與視圖之間的橋梁,將模型與視圖分離開來,對view 和model 進行調(diào)度操作祝谚。
  /**
 * 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.網(wǎng)絡(luò)訪問: 采用rxjava+retrofit+gson進行網(wǎng)絡(luò)訪問,并輕松的將json轉(zhuǎn)為對象,結(jié)構(gòu)清晰,使用方便.

  • 在APIService中初始化retrofit
 /**
 * 調(diào)用后臺的接口,架構(gòu)網(wǎng)絡(luò)層采用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" ;//服務(wù)器端口
    /**
     * 基礎(chǔ)地址
     * 初始化 retroft
     */
    private static final Retrofit sRetrofit = new Retrofit.Builder()
            .baseUrl(URL_HOST)
            .addConverterFactory(GsonConverterFactory.create())
            .addCallAdapterFactory(RxJavaCallAdapterFactory.create()) // 使用RxJava作為回調(diào)適配器
            .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;
    }

    /**********************仿照上面的方法,進行請求數(shù)據(jù)****************************/
    
  • 用retrofit訪問 返回observable的對象
public interface RetrofitRequest {


    boolean isTest=true; //是否在測試環(huán)境下
    //發(fā)布之前更改
    String BASE_URL_TEST = "/flyapptest/";//測試服務(wù)器
    String BASE_URL_OFFICAL = "/flyapp/";//正式服務(wù)器

    String BASE_URL = isTest?BASE_URL_TEST:BASE_URL_OFFICAL;//發(fā)布服務(wù)器


    /**
     * 登錄返回(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響應(yīng)式框架進行優(yōu)雅的異步處理,簡化代碼邏輯,并且很好的解決內(nèi)存泄漏 問題.(相關(guān)模塊在TakePhoto業(yè)務(wù)中)

  /**
     * 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 {//通知調(diào)用  并返回string
                return savePic(data);//此方法在io線程中調(diào)用 并返回
            }
        });

        saveSubscription = saveObservable
                .subscribeOn(Schedulers.io())//observable在調(diào)度中的IO線程中進行調(diào)度進行
                .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) {//帶參數(shù)的下一步,在此就是當(dāng)
                        Log.e("Tlog-->", "s-->" + s);
                        EventBus.getDefault().post(new EventUtils.ObjectEvent(bitmap));

                    }
                });
    }

4.事件訂閱: 采用EventBus作為事件總線,進行線程間,組件之間的通信.

/**
 * 事件總線 用于組件或線程通信,可替代回調(diào),廣播等
 * Created by ccj on 2016/4/14.
 */
public class EventUtils {

    /**
     * object類型(即傳統(tǒng)的所有類型,都可以強轉(zhuǎn)進行傳遞事件)
     */
    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.代碼分包: 根據(jù)業(yè)務(wù)區(qū)分進行分包,便于對代碼進行管理 .

這里寫圖片描述

6. 工具類: TDeviceUtils設(shè)備狀態(tài)的工具類,,SeriliazebleUtils 序列化工具類,SharepreferenceUtils保存工具類,
相關(guān)請參考代碼

7.app棧管理: 基于baseActivity,很好的釋放內(nèi)存,管理內(nèi)存.
相關(guān)請參考代碼


待后期完成

異常捕獲(待完善)
測試框架Espresso/JUnit/Mockito/Robolectric (待完善)


總結(jié)

1.層次分明宪迟,各層級之間都不管對方如何實現(xiàn),只關(guān)注結(jié)果交惯;
2.在視圖層(Presentation Layer)使用MVP架構(gòu)次泽,使原本臃腫的Activity(或Fragment)變得簡單,其處理方法都交給了Presenter席爽。
3.易于做測試意荤,只要基于每個模塊單獨做好單元測試就能確保整體的穩(wěn)定性。
4.易于快速迭代只锻,基于代碼的低耦合玖像,只需在業(yè)務(wù)邏輯上增加接口,然后在相應(yīng)的層級分別實現(xiàn)即可齐饮,絲毫不影響其他功能捐寥。

Blog-link

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

git-link

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

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市祖驱,隨后出現(xiàn)的幾起案子握恳,更是在濱河造成了極大的恐慌,老刑警劉巖捺僻,帶你破解...
    沈念sama閱讀 219,427評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件乡洼,死亡現(xiàn)場離奇詭異,居然都是意外死亡匕坯,警方通過查閱死者的電腦和手機束昵,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,551評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來葛峻,“玉大人锹雏,你說我怎么就攤上這事∨⑶福” “怎么了逼侦?”我有些...
    開封第一講書人閱讀 165,747評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長腰耙。 經(jīng)常有香客問我,道長铲球,這世上最難降的妖魔是什么挺庞? 我笑而不...
    開封第一講書人閱讀 58,939評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮稼病,結(jié)果婚禮上选侨,老公的妹妹穿的比我還像新娘掖鱼。我一直安慰自己,他們只是感情好援制,可當(dāng)我...
    茶點故事閱讀 67,955評論 6 392
  • 文/花漫 我一把揭開白布戏挡。 她就那樣靜靜地躺著,像睡著了一般晨仑。 火紅的嫁衣襯著肌膚如雪褐墅。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,737評論 1 305
  • 那天洪己,我揣著相機與錄音妥凳,去河邊找鬼。 笑死答捕,一個胖子當(dāng)著我的面吹牛逝钥,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播拱镐,決...
    沈念sama閱讀 40,448評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼艘款,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了沃琅?” 一聲冷哼從身側(cè)響起磷箕,我...
    開封第一講書人閱讀 39,352評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎阵难,沒想到半個月后岳枷,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,834評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡呜叫,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,992評論 3 338
  • 正文 我和宋清朗相戀三年空繁,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片朱庆。...
    茶點故事閱讀 40,133評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡盛泡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出娱颊,到底是詐尸還是另有隱情傲诵,我是刑警寧澤,帶...
    沈念sama閱讀 35,815評論 5 346
  • 正文 年R本政府宣布箱硕,位于F島的核電站拴竹,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏剧罩。R本人自食惡果不足惜栓拜,卻給世界環(huán)境...
    茶點故事閱讀 41,477評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧幕与,春花似錦挑势、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,022評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至诫给,卻和暖如春香拉,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背蝙搔。 一陣腳步聲響...
    開封第一講書人閱讀 33,147評論 1 272
  • 我被黑心中介騙來泰國打工缕溉, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人吃型。 一個月前我還...
    沈念sama閱讀 48,398評論 3 373
  • 正文 我出身青樓证鸥,卻偏偏與公主長得像,于是被迫代替她去往敵國和親勤晚。 傳聞我的和親對象是個殘疾皇子枉层,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,077評論 2 355

推薦閱讀更多精彩內(nèi)容