Arms是一個整合了大量主流開源項目的Android Mvp快速搭建框架

概述

MVPArms是一個整合了大量主流開源項目的Android Mvp快速搭建框架,其中包含Dagger2Retrofit,Rxjava以及Rxbinding,RxCacheRx系三方庫,而且提供UI自適應方案,本框架將它們結合起來,並所有使用Dagger2管理並提供給開發者使用,使用本框架開發你的項目就意味着你已經擁有一個MVP+Dagger2+Retrofit+Rxjava項目,發佈到github上能夠很是輕鬆的拿star(在簡歷中展露頭腳),我提供一切迭代和維護成本你只須要在Readme裏面註明框架出處,還不趕快行動?前端

特性

  • 自動生成MVP,Dagger2相關類
  • 版本更新
  • 更新日誌
  • 常見issues
  • 通用框架,適合全部類型的項目,支持大型項目的開發,Demo的包結構直接能夠拿來用
  • 所有使用Dagger2管理(將全部模塊使用Dagger鏈接起來,毫不是簡單的使用)
  • 大量使用Rxjava
  • 修改包名(common包不要修改)後就能夠直接使用,快速接入(老項目接入請按下面的步驟)
  • 所有UI自適應
  • 圖片加載類ImageLoader使用策略模式和建造者模式,輕鬆切換圖片加載框架和功能擴展
  • Model層提供Retrofit API和RxCache,是否使用緩存自行選擇
  • 全局http Request(請求參數,headersResponse(服務器返回的結果,headers,耗時)信息監聽,可解析json後根據狀態碼作相應的全局操做
  • 全局Rxjava錯誤處理,錯誤後自動重試,捕捉整個應用的全部錯誤

框架結構

包結構

開發須知

  • 開發者須要具備必定的Android開發能力
  • 開發者必須有使用Dagger2,Rxjava,Retrofit的經驗,沒使用過也必須瞭解,否則很難使用

Libraries簡介

  1. MvpGoogle官方出品的Mvp架構項目,含有多個不一樣的架構分支(此爲Dagger分支).
  2. Dagger2Google根據Square的Dagger1出品的依賴注入框架,經過apt動態生成代碼,性能優於用反射技術依賴注入的框架.
  3. Rxjava提供優雅的響應式Api解決異步請求.
  4. RxAndroid爲Android提供響應式Api.
  5. Rxlifecycle在Android上使用rxjava都知道的一個坑,就是生命週期的解除訂閱,這個框架經過綁定activity和fragment的生命週期完美解決.
  6. RxbindingJakeWharton大神的View綁定框架,優雅的處理View的響應事件.
  7. RxCache是使用註解爲Retrofit加入二級緩存(內存,磁盤)的緩存庫
  8. RetrofitSquare出品的網絡請求庫,極大的減小了http請求的代碼和步驟.
  9. Okhttp一樣Square出品,很少介紹,作Android都應該知道.
  10. Autolayout鴻洋大神的Android全尺寸適配框架.
  11. GsonGoogle官方的Json Convert框架.
  12. ButterknifeJakeWharton大神出品的view注入框架.
  13. Androideventbus一個輕量級使用註解的Eventbus.
  14. TimberJakeWharton大神出品Log框架,內部代碼極少,可是思想很是不錯.
  15. Glide此庫爲本框架默認封裝圖片加載庫,可參照着例子更改成其餘的庫,Api和Picasso差很少,緩存機制比Picasso複雜,速度快,適合處理大型圖片流,支持gfit,Fresco太大了!,在5.0一下優點很大,5.0以上系統默認使用的內存管理和Fresco相似.
  16. Realm速度和跨平臺性使它成爲現在最火的數據庫,美中不足的就是so庫太大
  17. LeakCanarySquare出品的專門用來檢測AndroidJava的內存泄漏,經過通知欄提示內存泄漏信息
  18. RxErroHandlerRxjava錯誤處理庫,可在出現錯誤後重試

 

1 開發準備

此框架適合本身作定製修改,全部暫時不上傳至JcenterMaven,請自行下載或clonejava

 

1.1 導入框架

compile project(':arms')

 

1.2 引用config.build

本框架提供一個引用大量第三方庫的config.gradle文件,用於第三方庫版本管理,將config.gradle複製進根目錄,並在項目的頂級build.gradle中引用它android

// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply from: "config.gradle" //這裏表示引用config.gradle文件
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.1.2'
 the individual module build.gradle files
    }
}

allprojects {
    repositories {
        jcenter()
        maven { url "https://jitpack.io" }//這裏要使用rxcahche指定的倉庫
    }
}

task clean(type: Delete) {
    delete rootProject.buildDir
}

 

1.2.1 使用config.build

由於在頂級build.gradle中引用了它,因此在整個項目的全部build.gradle中均可以使用rootProject.xxx來使用它裏面的內容git

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    testCompile rootProject.ext.dependencies["junit"]
    compile rootProject.ext.dependencies["support-v4"]
    compile rootProject.ext.dependencies["gson"]
    compile rootProject.ext.dependencies["appcompat-v7"]
    compile rootProject.ext.dependencies["cardview-v7"]
    compile rootProject.ext.dependencies["autolayout"]
    compile rootProject.ext.dependencies["butterknife"]
    compile rootProject.ext.dependencies["androideventbus"]
    }

也可使用它來管理一些項目的信息,這樣有多個module也能夠直接使用一個信息github

android {
    compileSdkVersion rootProject.ext.android["compileSdkVersion"]
    buildToolsVersion rootProject.ext.android["buildToolsVersion"]
    useLibrary 'org.apache.http.legacy'

    defaultConfig {
        minSdkVersion rootProject.ext.android["minSdkVersion"]
        targetSdkVersion rootProject.ext.android["targetSdkVersion"]
        versionCode rootProject.ext.android["versionCode"]
        versionName rootProject.ext.android["versionName"]
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

 

1.3 依賴Dagger2

本框架所有使用Dagger2管理,因此必須依賴Dagger2,找到app的build.gradle,加入以下代碼數據庫

apply plugin: 'com.android.application'
apply plugin: 'com.neenbedankt.android-apt'//使用apt插件

buildscript {
    repositories {
        jcenter()
        mavenCentral()
    }
    dependencies {
        classpath 'com.neenbedankt.gradle.plugins:android-apt:1.8'//使用apt
    }
}


dependencies {
      apt rootProject.ext.dependencies["dagger2-apt-compiler"]//依賴apt插件
    provided rootProject.ext.dependencies["javax.annotation"]//dagger2必須依賴jsr250 annotation
}

 

1.4 配置AndroidManifest

 

1.4.1 添加權限

<uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

 

1.4.2 配置Autolayout Meta

使用Autolayout 自適應框架必須配置Meta屬性及設計圖的寬高,詳情參考Autolayoutapache

//將設計圖的寬高配置後,配合AutoLauout控件使用,在設計圖尺寸之外的其它尺寸手機上,也能達到和設計圖同樣的顯示效果
        <meta-data
            android:name="design_width"
            android:value="1080"/>
        <meta-data
            android:name="design_height"
            android:value="1920"/>

 

1.4.3 引用Glide自定義屬性

本框架默認使用Glide加載圖片,但提供一個管理器ImageLoader提供統一接口,使用策略者模式可輕鬆替換圖片加載框架,本框架默認提供Glide的自定義緩存配置信息,使用它以前先引用它的自定義配置信息json

<!--glide配置-->
        <meta-data
            android:name="com.jess.arms.widget.imageloader.glide.GlideConfiguration"
            android:value="GlideModule"/>

 

1.5 混淆

因爲本框架依賴大量三方庫,因此已經在arms Module下的proguard-rules.pro中提供了全部規則,若是想使用它,請複製它替換app Module中的proguard-rules.pro,混淆時能夠根據本身的需求修改或添加規則,混淆前務必注意將Java Bean,自定義組件添加進規則緩存

 

1.6 版本更新

! 必定不能修改common包的包名,舊版本須要找到和common包下同名的類並刪除,而後從新引用common包裏的類服務器

若是你得到本框架的方式是經過clone或者下載:

  1. 直接能夠經過命令行git pull origin master拉取最新的版本並自動合併
  2. 若是你修改了包名還得執行命令git rm --cache -r app/src/main/java/me/jessyan/mvparms,下次拉取時就不會拉取Demo的內容

若是你得到本框架的方式是經過fork到本身倉庫後,clone或下載:

  1. git remote add arms https://github.com/JessYanCoding/MVPArms.git  添加遠程倉庫,arms是遠程倉庫的代號,可自定義,之後都經過這個代號對遠程倉庫做操做
  2. git fetch arms拉取遠程倉庫最新的版本
  3. git merge arms/master --allow-unrelated-histories合併遠程倉庫到當前分支
  4. 後面若是本框架有更新就只用重複2,3步,--allow-unrelated-histories只用在第一次合併時添加
  5. 若是你修改了包名還得執行命令git rm --cache -r app/src/main/java/me/jessyan/mvparms,下次拉取時就不會拉取Demo的內容

 

2 快速開始

 

2.1 繼承BaseApplication

新建項目的Application繼承自BaseApplication,並在AndroidManifest中聲明

//BaseApplication爲抽象類,必須實現getGlobeConfigModule,這裏返回整個應用須要的配置信息(將app的全局配置信息封裝進module,使用Dagger注入到須要配置信息的地方)
    @Override
    protected GlobeConfigModule getGlobeConfigModule() {
    return GlobeConfigModule
                .buidler()
                .baseurl(Api.APP_DOMAIN)//必須提供baseurl
                .build();
    }

 

2.1.1 AppComponent

Application生命週期是和App是同樣的,因此是適合提供一些單例對象,本框架使用Dagger2管理,因此使用AppComponent來提供全局全部的單例對象

  • 建立AppComponent接口
@Singleton
@Component(modules = {AppModule.class, ClientModule.class, ServiceModule.class, ImageModule.class, CacheModule.class, GlobeConfigModule.class})
public interface AppComponent {
    Application Application();

    //服務管理器,retrofitApi
    ServiceManager serviceManager();

    //緩存管理器
    CacheManager cacheManager();

    //Rxjava錯誤處理管理類
    RxErrorHandler rxErrorHandler();

    OkHttpClient okHttpClient();

    //圖片管理器,用於加載圖片的管理類,默認使用glide,使用策略模式,可替換框架
    ImageLoader imageLoader();

    //gson
    Gson gson();

    //用於管理全部activity
    AppManager appManager();
}
  • 構造AppComponent對象
@Override
    public void onCreate() {
        super.onCreate();
 mAppComponent = DaggerAppComponent
                .builder()
                .appModule(getAppModule())//baseApplication提供
                .clientModule(getClientModule())//baseApplication提供
                .globeConfigModule(getGlobeConfigModule())//全局配置
                .imageModule(getImageModule())//baseApplication提供
                .serviceModule(new ServiceModule())//需自行建立
                .cacheModule(new CacheModule())//需自行建立
                .build();
 }
 //將AppComponent返回出去,供其它地方使用, AppComponent接口中聲明的方法返回的實例, 在getAppComponent()拿到對象後均可以直接使用
  public AppComponent getAppComponent() {
        return mAppComponent;
    }

 

2.1.2 ServiceModule

ServiceModule提供RetrofitApi對應的Service,這些Service對象在AppComponent中注入ServiceManager(需繼承BaseServiceManager)中統一管理

  • 自行定義Retrofit Service以下,熟練Retrofit請忽略
public interface CommonService {

    String HEADER_API_VERSION = "Accept: application/vnd.github.v3+json";

    @Headers({HEADER_API_VERSION})
    @GET("/users")
    Observable<List<User>> getUsers(@Query("since") int lastIdQueried, @Query("per_page") int perPage);
}
  • 定義ServiceModule,這裏使用Retrofit對象(ClientModule提供)實例化Service接口,提供全部Service對象(能夠根據不一樣的邏輯劃分多個Service接口)
@Module
public class ServiceModule {

    @Singleton
    @Provides
    CommonService provideCommonService(Retrofit retrofit) {
        return retrofit.create(CommonService.class);
    }

}
  • AppComponent將全部的Service注入到ServiceManager中,全部Model層均可以拿到此對象,意味着每一個Model均可以請求任意Api
@Singleton
public class ServiceManager implements BaseServiceManager {
    private CommonService mCommonService;

//若是須要添加service只需在構造方法中添加對應的service,
在提供get方法返回出去,只要在ServiceModule提供了該service Dagger2會自行注入
    @Inject public ServiceManager(CommonService commonService){
        this.mCommonService = commonService;
    }

    public CommonService getCommonService() {
        return mCommonService;
    }
}

 

2.1.3 CacheModule

Cache層默認使用RxCache,CacheModule提供RetrofitApi對應的Cache對象,這些Cache對象在AppComponent中注入CacheManager(需繼承BaseCacheManager)中統一管理

  • 自行定義RxCache Provider以下,熟練RxCache請忽略
public interface CommonCache {

    @LifeCache(duration = 2, timeUnit = TimeUnit.MINUTES)
    Observable<Reply<List<User>>> getUsers(Observable<List<User>> oUsers, DynamicKey idLastUserQueried, EvictProvider evictProvider);

}
  • 定義CacheModule,這裏使用RxCache對象(ClientModule提供)實例化全部Cache接口,提供全部Cache對象
@Module
public class CacheModule {

    @Singleton
    @Provides
    CommonCache provideCommonService(RxCache rxCache) {
        return rxCache.using(CommonCache.class);
    }


}
  • AppComponent將全部的Cache注入到CacheManager中,全部Model層均可以拿到全部的Cache對象
@Singleton
public class CacheManager implements BaseCacheManager{
    private CommonCache mCommonCache;

//若是須要添加Cache只需在構造方法中添加對應的Cache,
在提供get方法返回出去,只要在CacheModule提供了該Cache Dagger2會自行注入
    @Inject public CacheManager(CommonCache commonCache) {
        this.mCommonCache = commonCache;
    }

    public CommonCache getCommonCache() {
        return mCommonCache;
    }
}

 

2.2 繼承BaseActivity

讓項目的基類Activity繼承BaseActivity,BaseActivity默認注入Presenter,因此若是要使用Presenter必須指定對應的範型,而且提供注入Presenter所須要的Component

public abstract class WEActivity<P extends BasePresenter> extends BaseActivity<P> {
    protected WEApplication mWeApplication;
    @Override
    protected void ComponentInject() {
        mWeApplication = (WEApplication) getApplication();
        setupActivityComponent(mWeApplication.getAppComponent());
    }
    //提供AppComponent(提供全部的單例對象)給子類,進行Component依賴
    protected abstract void setupActivityComponent(AppComponent appComponent);
}

 

2.3 繼承BaseFragment

讓項目的基類Fragment繼承BaseFragment,BaseFragment默認注入Presenter,因此若是要使用Presenter必須指定對應的範型,而且提供注入Presenter所須要的Component

public abstract class WEFragment<P extends BasePresenter> extends BaseFragment<P> {
    protected WEApplication mWeApplication;
    @Override
    protected void ComponentInject() {
        mWeApplication = (WEApplication)mActivity.getApplication();
        setupFragmentComponent(mWeApplication.getAppComponent());
    }

    //提供AppComponent(提供全部的單例對象)給子類,進行Component依賴
    protected abstract void setupFragmentComponent(AppComponent appComponent);
}

 

2.4 MVP實戰

定義業務邏輯MVP,繼承MVP各自的基類便可,這裏能夠稍微粗力度的定義MVP類,即無需每一個FragmentActivity(每一個頁面)都定義不一樣的MVP類,能夠按照相同的業務邏輯使用一組MVP

 

2.4.1 Contract

這裏根據Google官方的MVP項目,能夠在Contract中定義MVP的接口,便於管理,此框架無需定義Presenter接口,因此Contract只定義ModelView的接口

public interface UserContract {
    //對於常用的關於UI的方法能夠定義到BaseView中,如顯示隱藏進度條,和顯示文字消息
    interface View extends BaseView {
        void setAdapter(DefaultAdapter adapter);
        void startLoadMore();
        void endLoadMore();
    }
    //Model層定義接口,外部只需關心model返回的數據,無需關心內部細節,及是否使用緩存
    interface Model extends IModel{
        Observable<List<User>> getUsers(int lastIdQueried, boolean update);
    }
}

 

2.4.2 View

通常讓ActivityFragment實現Contract中定義的View接口,供Presenter調用對應方法操做UI,BaseActivity默認注入Presenter,如想使用Presenter,必須指定Presenter的範型,和實現setupActivityComponent來提供Presenter須要的ComponentModule

public class UserActivity extends WEActivity<UserPresenter> implements UserContract.View {

    @Override
    protected void setupActivityComponent(AppComponent appComponent) {
        DaggerUserComponent
                .builder()
                .appComponent(appComponent)
                .userModule(new UserModule(this))
                .build()
                .inject(this);

    }

    @Override
    protected View initView() {
        return LayoutInflater.from(this).inflate(R.layout.activity_user, null, false);
    }

    @Override
    protected void initData() {
       }
}

 

2.4.3 Model

Model實現ContractModel接口,而且繼承BaseModel,指定範型爲,上面定義的ServiceManagerCacheManager,而後經過兩個Manager拿到須要的ServiceCachePresenter提供須要的數據(是否使用緩存請自行選擇)

@ActivityScope
public class UserModel extends BaseModel<ServiceManager,CacheManager> implements UserContract.Model{
    private CommonService mCommonService;
    private CommonCache mCommonCache;

    @Inject
    public UserModel(ServiceManager serviceManager, CacheManager cacheManager) {
        super(serviceManager, cacheManager);
        this.mCommonService = mServiceManager.getCommonService();
        this.mCommonCache = mCacheManager.getCommonCache();
    }

    @Override
    public Observable<List<User>> getUsers(int lastIdQueried, boolean update) {

    }

}

 

2.4.4 Presenter

PresenterMVP中的大部分的做用爲經過從Model層接口獲取數據,在調用View層接口顯示數據,首先實現BasePresenter,指定ModelView的範型,注意必定要指定Contract中定義的接口,Presenter須要的ModelView,都使用Dagger2注入,這樣即解藕又方便測試,怎麼注入?

@ActivityScope
public class UserPresenter extends BasePresenter<UserContract.Model, UserContract.View> {

    @Inject
    public UserPresenter(UserContract.Model model, UserContract.View rootView) {
        super(model, rootView);
    }
    //這裏定義業務方法,相應用戶的交互
    public void requestUsers(final boolean pullToRefresh) {
    }
}

 

2.4.5 MVP Module

這裏的Module提供當前業務邏輯對應的ViewModel接口(Contract中定義的接口)的實現類,Model須要AppComponent中提供的ServiceManagerCacheManager來實現網絡請求和緩存,因此須要經過Component依賴AppComponent拿到這兩個Manager

@Module
public class UserModule {
    private UserContract.View view;

    //構建UserModule時,將View的實現類傳進來,這樣就能夠提供View的實現類給presenter
    public UserModule(UserContract.View view) {
        this.view = view;
    }


    @ActivityScope
    @Provides
    UserContract.View provideUserView(){
        return this.view;
    }

    @ActivityScope
    @Provides
    UserContract.Model provideUserModel(UserModel model){
        return model;
    }
}

 

2.4.6 MVP Component

這裏須要注意的是此Component必須依賴AppComponent,這樣才能提供Model須要的ServiceManagerCacheManager,提供inject()方法就能將ModuleAppComponent中提供的對象注入到對應的類中,inject()中的參數不能是接口,怎麼注入?

@ActivityScope
@Component(modules = UserModule.class,dependencies = AppComponent.class)
public interface UserComponent {
    void inject(UserActivity activity);
}

 

2.4.7 Dagger Scope

在上面的代碼中ActivityScope大量出如今ModuleComponent中,Dagger2使用Scope限制每一個Module中提供的對象的生命,Dagger2默認只提供一個@SingletonScope即單例,本框架提供@ActvityScope@FragmentScope,若有其餘需求請自行實現,ModuleComponent定義相同的ScopeModule中提供的對象的生命週期會和Component中同樣(即在Component生命週期內,如需使用到Moudle中提供的對象,只會調用一次@Provide註解的方法獲得此對象)

 

2.4.8 MVP總結

  • 之後每一個業務邏輯都重複構造這些類,只是換個名字而已,值得注意的是MVP剛開始用時確實會以爲無緣無故多了不少類,很是繁瑣麻煩,可是等頁面代碼邏輯越來多時,你會發現其中的好處,邏輯清晰,解耦,便於團隊協做,測試容易,錯誤好定位,因此如今本框架提供Template自動生成代碼解決這個痛點,讓開發者更加愉快的使用本框架

 

3 功能使用

 

3.1 App全局配置信息(使用Dagger注入)

GlobeConfigModule使用建造者模式將App的全局配置信息封裝進Module(使用Dagger注入到須要配置信息的地方),能夠配置CacheFile,InterCeptor等,由於使用的是建造者模式因此如你有其餘配置信息須要使用Dagger注入,直接就能夠添加進Builder而且不會影響到其餘地方

//如需添加個Boolean字段提供給Log工具類,來判斷是否打印Log
    @Module
    public class GlobeConfigModule {
        private Boolean isLog;

        private GlobeConfigModule(Buidler buidler) {
            this.isLog = builder.isLog
        }

        public static Buidler buidler() {
        return new Buidler();
       }

        public static final class Buidler {
            private Boolean isLog;

            private Buidler() {}

            //1.給Builder中添加個方法接受isLog字段
            public Buidler isLog(Boolean isLog) {
              this.isLog = isLog;
              return this;
           }

            public GlobeConfigModule build() {
               return new GlobeConfigModule(this);
           }

        }

        //2.使用@Provides,將isLog返回出去,供Dagger注入到Log工具類
        @Singleton
        @Provides
        Boolean provideIsLog() {
            return isLog;
        }


    }

 

3.2 全局捕捉Http請求和響應

經過GlobeConfigModule.globeHttpHandler()方法傳入GlobeHttpHandler

@Override
    protected GlobeConfigModule getGlobeConfigModule() {
        return GlobeConfigModule
                .buidler()
                .baseurl(Api.APP_DOMAIN)
                .globeHttpHandler(new GlobeHttpHandler() {// 這裏能夠提供一個全局處理http響應結果的處理類,
                    // 這裏能夠比客戶端提早一步拿到服務器返回的結果,能夠作一些操做,好比token超時,從新獲取
                    @Override
                    public Response onHttpResultResponse(String httpResult, Interceptor.Chain chain, Response response) {
                        //這裏能夠先客戶端一步拿到每一次http請求的結果,能夠解析成json,作一些操做,如檢測到token過時後
                        //從新請求token,並從新執行請求
                        try {
                            if (!TextUtils.isEmpty(httpResult)) {
                                JSONArray array = new JSONArray(httpResult);
                                JSONObject object = (JSONObject) array.get(0);
                                String login = object.getString("login");
                                String avatar_url = object.getString("avatar_url");
                                Timber.tag(TAG).w("result ------>" + login + "    ||   avatar_url------>" + avatar_url);
                            }

                        } catch (JSONException e) {
                            e.printStackTrace();
                            return response;
                        }


                        //這裏若是發現token過時,能夠先請求最新的token,而後在拿新的token放入request裏去從新請求
                        //注意在這個回調以前已經調用過proceed,因此這裏必須本身去創建網絡請求,如使用okhttp使用新的request去請求
                        // create a new request and modify it accordingly using the new token
//                    Request newRequest = chain.request().newBuilder().header("token", newToken)
//                            .build();

//                    // retry the request
//
//                    response.body().close();
                        //若是使用okhttp將新的請求,請求成功後,將返回的response  return出去便可

                        //若是不須要返回新的結果,則直接把response參數返回出去
                        return response;
                    }

                    // 這裏能夠在請求服務器以前能夠拿到request,作一些操做好比給request統一添加token或者header
                    @Override
                    public Request onHttpRequestBefore(Interceptor.Chain chain, Request request) {
                        //若是須要再請求服務器以前作一些操做,則從新返回一個作過操做的的requeat如增長header,不作操做則返回request

                        //return chain.request().newBuilder().header("token", tokenId)
//                .build();
                        return request;
                    }
                })
                .build();
    }

 

3.3 全局錯誤處理及發生錯誤時從新執行

若是須要使用Rxjava的全局錯誤處理,需經過GlobeConfigModule.responseErroListener()方法傳入ResponseErroListener,並在每次使用Rxjava調用subscribe時,使用ErrorHandleSubscriber,並傳入AppComponent中提供的RxErrorHandler,此Subscribe,默認已經實現OnError方法,如想自定義能夠重寫OnError方法

@Override
  protected GlobeConfigModule getGlobeConfigModule() {
        return GlobeConfigModule
                .buidler()
                .baseurl(Api.APP_DOMAIN)   
                   .responseErroListener(new ResponseErroListener() {
                    //     用來提供處理全部錯誤的監聽
                    //     rxjava必要要使用ErrorHandleSubscriber(默認實現Subscriber的onError方法),此監聽才生效
                    @Override
                    public void handleResponseError(Context context, Exception e) {
                        Timber.tag(TAG).w("------------>" + e.getMessage());
                        UiUtils.SnackbarText("net error");
                    }
                }).build();
    }
  • Rxjava中使用
Observable
                .just(1)
                .retryWhen(new RetryWithDelay(3,2))//遇到錯誤時重試,第一個參數爲重試幾回,第二個參數爲重試的間隔
                .subscribe(new ErrorHandleSubscriber<Integer>(mErrorHandler) {
            @Override
            public void onNext(Integer Integer) {

            }
        });

 

3.4 切換圖片請求框架

本框架默認使用Glide實現圖片加載功能,使用ImagerLoader提供統一的接口,ImagerLoader使用策略模式和建造者模式,能夠動態切換圖片框架(好比說切換成Picasso),而且加載圖片時傳入的參數也能夠隨意擴展(loadImage方法在須要擴展參數時,也不須要改動,所有經過Builder擴展,好比你想讓內部的圖片加載框架,清除緩存你只須要定義個boolean字段,內部根據這個字段if|else,其餘操做同理)

  • 使用ImageLoader必須傳入一個實現了BaseImageLoaderStrategy接口的圖片加載實現類從而實現動態切換,因此首先要實現BaseImageLoaderStrategy,實現時必須指定一個繼承自ImageConfig的實現類,使用建造者模式,能夠儲存一些信息,好比URLImageView,Placeholder等,能夠不斷的擴展,供圖片加載框架使用
public class PicassoImageLoaderStrategy implements BaseImageLoaderStrategy<PicassoImageConfig> {
     @Override
    public void loadImage(Context ctx, PicassoImageConfig config) {
    Picasso.with(ctx)
                .load(config.getUrl())
                .into(config.getImageView());
    }
}
  • 實現ImageCofig使用建造者模式
public class PicassoImageConfig extends ImageConfig{

    private PicassoImageConfig(Buidler builder) {
        this.url = builder.url;
        this.imageView = builder.imageView;
        this.placeholder = builder.placeholder;
        this.errorPic = builder.errorPic;
    }

    public static Buidler builder() {
        return new Buidler();
    }


    public static final class Buidler {
        private String url;
        private ImageView imageView;
        private int placeholder;
        protected int errorPic;

        private Buidler() {
        }

        public Buidler url(String url) {
            this.url = url;
            return this;
        }

        public Buidler placeholder(int placeholder) {
            this.placeholder = placeholder;
            return this;
        }

        public Buidler errorPic(int errorPic){
            this.errorPic = errorPic;
            return this;
        }

        public Buidler imagerView(ImageView imageView) {
            this.imageView = imageView;
            return this;
        }

        public PicassoImageConfig build() {
            if (url == null) throw new IllegalStateException("url is required");
            if (imageView == null) throw new IllegalStateException("imageview is required");
            return new PicassoImageConfig(this);
        }
    }
}
  • ImageLoader構造時能夠傳入PicassoImageLoaderStrategy(),也能夠經過AppComponent拿到ImageLoader對象後,setLoadImgStrategy(new PicassoImageLoaderStrategy)替換以前的實現(默認使用Glide)
方法一 在ImageModule中返回PicassoImageLoaderStrategy
@Module
public class ImageModule {

    @Singleton
    @Provides
    public BaseImageLoaderStrategy provideImageLoaderStrategy() {
        return new PicassoImageLoaderStrategy();
    }

    @Singleton
    @Provides
    public ImageLoader provideImageLoader(BaseImageLoaderStrategy strategy) {
        return new ImageLoader(strategy);
    }
}

方法2 拿到AppComponent中的 ImagerLoader
mApplication
    .getAppComponent()
    .imageLoader()
    .setLoadImgStrategy(new PicassoImageLoaderStrategy());


使用方法

mApplication
    .getAppComponent()
    .imageLoader()
    .loadImage(mApplication, GlideImageConfig
                .builder()
                .url(data.getAvatarUrl())
                .imagerView(mAvater)
                .build());

 

3.5 AndroidEventBus Tag

本框架使用AndroidEventBus實現事件總線,此框架使用註解標記目標方法,統一將Tag的常量寫到EventBusTag接口中,便於管理,若是要在當前對象中使用AndroidEventBus請在須要使用的Activity,Fragment,Presenter中重寫useEventBus(),返回true表明使用,默認返回true

 

3.6 AutoLayout組件

本框架使用AutoLayout框架,實現控件自適應,此框架要讓組件自適應,必須讓它的父控件,從新測量,和重寫LayoutParams,而官方只默認提供了三個ViewGroup,AutoRelativeLayout,AutoLinearLayout,AutoFrameLayout實現了這些操做,爲了方便開發者使用,本框架提供了一些經常使用的AutoLayout組件,在框架的widget包下的autolayout包中,在xml中引用便可使子控件自適應,而且還提供一個 Template(在最後面)用於生成自適應所須要的的Auto系列View,如須要使ScrollView的子控件自適應,使用此Template輸入ScrollView,便可生成AutoScrollView,在xml中引用便可

 

3.7 自定義PopupWindow

框架提供一個建造者模式的自定義PopupWindow組件CustomPopupWindow,本身實現佈局後就能夠直接使用這個實現PopupWindow,使用建造者模式,隨意擴展自定義參數

 

3.8 快速實現RecycleView

本框架提供DefaultAdapterBaseHolder基類快速實現Recycleview.

  • BaseHolder默認初始化了ButterKnifeAutoLayout,繼承後不只能夠直接注入View,佈局還能夠自適應屏幕
  • RecycleView默認是不提供Item的點擊事件的,使用DefaultAdapter調用setOnItemClickListener能夠實現Item的點擊事件

 

3.9 權限管理(適配Android6.0權限管理)

本框架使用RxPermissions用於權限管理(適配android6.0),並提供PermissionUtil工具類一行代碼實現權限請求.適配Android6.0權限管理詳解

PermissionUtil.launchCamera(new RequestPermission() {
            @Override
            public void onRequestPermissionSuccess() {
                launchCapture();//請求權限成功後作一些操做
            }
        }, mRxPermissions, mRootView, mErrorHandler);

 

3.10 Gradle配置啓動DeBug模式

在主項目(app)的build.gradle中配置是否開啓打印Log或則是否使用LeakCanary,等調試工具

  • 在build.gradle中配置
android {

    buildTypes {

        debug {
        //這兩個變量是自定義的,本身也能夠自定義字段,他會默認配置到BuildConfig中,app中能夠根據這些字段執行一些操做
            buildConfigField "boolean", "LOG_DEBUG", "true"
            buildConfigField "boolean", "USE_CANARY", "true"
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }

        release {
            buildConfigField "boolean", "LOG_DEBUG", "false"
            buildConfigField "boolean", "USE_CANARY", "false"
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
  • 在代碼中使用(好比在application中作一些初始化設置)
public class WEApplication extends BaseApplication {

@Override
    public void onCreate() {
        if (BuildConfig.LOG_DEBUG) {//Timber日誌打印
                    Timber.plant(new Timber.DebugTree());
                }
        if (BuildConfig.USE_CANARY) {//leakCanary內存泄露檢查
                    LeakCanary.install(this);
                }
     } 
}

 

3.11 AppManager(管理全部的Activity)

AppManager用於管理全部的Activity,內部持有一個含有全部存活的Activity(未調用onDestroy)的List,和一個當前在最前端的Activity(未調用onPause),AppManager封裝有多種方法,能夠很方便的對它們進行操做,也能夠在未持有AppManager的狀況下,經過EventBus遠程遙控它的全部方法,這樣咱們能夠在整個app的任何地方對任何Activity進行全局操做,好比在app請求網絡超時時讓最前端的Activity顯示鏈接超時的交互頁面(這個邏輯不用寫到當前請求的Activity裏,能夠在一個單例類裏作全局的統一操做,由於能夠隨時經過AppManager拿到當前的Activity)

  • 遠程遙控經過EventBuspost Message實現,經過不一樣的what區分不一樣的方法和Handler同理,能夠根據本身的需求適當的在AppManager中添加對應的方法
/**
     * 經過eventbus post事件,遠程遙控執行對應方法
     */
    @Subscriber(tag = APPMANAGER_MESSAGE, mode = ThreadMode.MAIN)
    public void onReceive(Message message) {
        switch (message.what) {
            case START_ACTIVITY:
                dispatchStart(message);
                break;
            case SHOW_SNACKBAR:
                showSnackbar((String) message.obj, message.arg1 == 0 ? false : true);
                break;
            case KILL_ALL:
                killAll();
                break;
            case APP_EXIT:
                AppExit();
                break;
        }
    }

Acknowledgements

感謝本框架所使用到的全部三方庫的Author,以及全部爲Open Sourece作無私貢獻的DeveloperOrganizations,使咱們能更好的工做和學習,本人也會將業餘時間回報給開源社區

wiki原文地址:https://github.com/JessYanCoding/MVPArms/wiki

相關文章
相關標籤/搜索