cool hit counter See so many MVP+Dagger2+Retrofit+Rxjava projects, easy to get star, heartbeat?_Intefrankly

See so many MVP+Dagger2+Retrofit+Rxjava projects, easy to get star, heartbeat?


Original article address: http://www.jianshu.com/p/4bbecd0bb027

Logo

summarize

MVPArms be一个整合了大量主流开源 sports event of Android MVP Quick Framework, which contains Dagger2 , Retrofit , Rxjava and RxLifecycle , RxCache etc. Rx Department's tripartite repository, and provides UI adaptive scheme, this framework combines them and uses all Dagger2 Managed and available to developers, using this framework to develop your project means you already have a MVP + Dagger2 + Retrofit + Rxjava sports event

MVPArt be一个新 of MVP architecture, suitable for small and medium-sized projects, designed to solve traditional MVP There are too many classes and interfaces, and Presenter harmony View Communication through the interface is too cumbersome, reuse Presenter 代价太大 etc.问题

notices

Extensions, check it out:

characteristics

  • Generic framework, suitable for all types of projects, support for large projects, compatible with component-based development, can be used as a component-based Base warehouse
  • Base The base class (BaseActivity, BaseFragment, BaseApplication ...)
  • MVP The base class (IModel, IVIew, IPresenter ...)
  • The frame is highly customizable (ConfigModule ), the framework source code can be modified without modifying the Retoift, Okhttp, RxCache, Gson etc.框架 of特有属性进行自定义化 configure, 可 (located) at不修改框架源码 of情况下向 BaseApplication, BaseActivity, BaseFragment and the framework's unique ConfigModule configure kind, 可 (located) at不修改框架源码 of情况下 because of框架轻松扩展任何新增功能
  • ingenious RxLifeCycle Application method, which can be used without inheriting RxLifeCycle offered Activity harmony Fragment In the case of normal use RxLifeCycle All functions of the
  • The original builder model Module (GlobalConfigModule ), can be implemented using Dagger2 Inject custom parameters anywhere into the framework, easily extend any custom parameters
  • security situation use Dagger2 Management (use all modules with Dagger2 Connected, never simply used)
  • security situation监听整个 App all Activity and Fragment (including three-party libraries), and can insert arbitrary code into its lifecycle
  • security situation监听 Http Request (Request parameters, Headers ...), Response (服务器返回 of结果, Headers, 耗时 ...) etc.信息(包括 Glide of请求), 可解析 json back根据状态码做相应 of security situation操作 and数据加密, Cookie Operations such as management
  • security situation管理 all Activity (包括三方 warehouse of Activity ), which can be achieved throughout the App Anywhere, Exit All Activity, and get hold of前台 Activity Do the appropriate actions (e.g., you can add a new file to the App Any position to do pop-ups Dialog of the operation)
  • security situation Rxjava 错误处理, 错误 back自动重试, 捕捉整个应用 of all错误
  • security situation UI adaptive
  • Image loading class ImageLoader use策略模式 harmony建造者模式, 轻松切换图片加载框架, 方便功能扩展
  • 网络请求 Log Printing封装(提供解析 back of服务器 of请求信息 harmony服务器 of响应信息, 按可自定义 of任意格式输出打印日志, 内置一个漂亮 of打印格式模板)
  • caching mechanism encapsulation of its own components within the framework (the framework can cache content components are provided with interfaces for external developers to customize the caching mechanism)
  • Code Generation Plugin (MVPArms 全家桶一键生成所 need of all kind documents)
  • Demo 修改包名 back就可以直接 use, 快速接入(老 sports event接入请按下面 of步骤)

framework structure

Architecture

package structure

package

Development Instructions

  • 开发者 need具有一定 of Android Development of skills, and self-problem-solving abilities
  • Developers must have access to Dagger2 , Rxjava , Retrofit If you have not used it before, you must understand it, otherwise it is difficult to get started.
  • 本框架 because of作者用业余时间维护,作者并没有义务 because of开发者做任何事, use时 perhaps提问时请保持对作者 and维护者起码 of revere harmony respect

Introduction to Libraries

  1. Mvp Officially produced by GoogleMvp架构 sports event,含有多个不同 of架构分支(此 because ofDagger分支).
  2. Dagger2 Google's Dependency Injection Framework based on Square's Dagger1 , which generates code at compile time via Apt, outperforms dependency injection frameworks that use runtime reflection techniques.
  3. Rxjava Provides an elegant responsive Api to address asynchronous requests and event handling.
  4. RxAndroid Responsive Api for Android.
  5. Rxlifecycle (located) atAndroid上 userxjava都知道 of一个坑,就 be生命周期 of解除订阅,这个框架 pass (a bill or inspection)绑定activity harmonyfragment of生命周期完美解决.
  6. RxCache be use注解 because ofRetrofit加入二级buffer memory(内存,磁盘) ofbuffer memory warehouse.
  7. RxErroHandler be Rxjava The error handling library can be retried after an error has occurred.
  8. RxPermissions Responsive library for handling Android runtime permissions.
  9. RetrofitSquare出品 of网络请求 warehouse,极大 of减少了http请求 of代码 harmony步骤.
  10. Okhttp The same Square production, not much introduction, do Android should know .
  11. Autolayout Hongyang Da Shen's Android Full Size Adaptation Framework.
  12. Gson Google's official Json Convert framework .
  13. Butterknife JakeWharton gods produced view injection framework .
  14. Androideventbus A lightweight use of annotated Eventbus.
  15. Timber JakeWharton gods produced Log framework container, very little internal code, but the idea is very good .
  16. Glide This library is the default package image loading library for this framework, you can refer to the example to change to other libraries, Api andPicasso Pretty much, the caching mechanism is better thanPicasso complex, fast, suitable for processing large image streams, supports gif imagesFresco It's too big! The advantage is great below 5.0, and systems above 5.0 use memory management by default andFresco Similarly.
  17. LeakCanary Square has produced a special test forAndroid harmonyJava The memory leak is indicated by the notification bar.

<a name="1"></a>

1 Development preparation

This framework recommends the direct use of Gradle 远程 depend on,框架已经提供了很多用于扩展 interfaces,足以满足日常需求,如非必须,请不要 use depend on Module way and modifying the framework source code

<a name="1.1"></a>

1.1 Introductory framework

compile 'me.jessyan:arms:2.4.1' // useRxjava2, 已兼容 AndroidStudio v3.0  and Gradle Plugin v3.0

--------------------------------------------

compile 'me.jessyan:arms:1.6.3' // useRxjava1 (请注意 Rxjava1  of版本以 back不再维护,建议 use Rxjava2 版本)

<a name="1.2"></a>

1.2 References config.build

This framework provides a reference to a large number of third-party librariesconfig.gradle documents,用于第三方 warehouse版本管理,将config.gradle Copy it into the root directory, and add it to the top level of the projectbuild.gradle Cite it in

// Top-level build file where you can add configuration options common to all sub-projects/modules.
apply from: "config.gradle" // Here it indicates a quoteconfig.gradle documents
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        //classpath 'com.android.tools.build:gradle:2.3.3'//Android Studio v2.3.3
        classpath 'com.android.tools.build:gradle:3.0.0' //Android Studio v3.0
    }
}

allprojects {
    repositories {
        jcenter()
        maven { url "https://jitpack.io" }//RxCache  need jitpack  warehouse
        maven { url "https://maven.google.com" }//Support-library  need Google  warehouse
        google() //AndroidStudio v3.0  Can be used google()  replace maven { url "https://maven.google.com" }
    }
}

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

<a name="1.2.1"></a>

1.2.1 useconfig.build

Because at the topbuild.gradleis referenced in it, so allbuild.gradle中都 Can be usedrootProject.xxx来 use它里面 content

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"]
    }

也 Can be used它来管理一些 sports event of信息,这样有多个module也可以直接 use同一个信息

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'
        }
    }
}

<a name="1.3"></a>

1.3 configureBuild.gradle

<a name="1.3.1"></a>

1.3.1 Dependency on Dagger2

The framework is managed using Dagger2, so you must rely on Dagger2, find the appbuild.gradle , add the following code

apply plugin: 'com.android.application'

buildscript {
    repositories {
        jcenter()
    }
}

dependencies {
    annotationProcessor rootProject.ext.dependencies["butterknife-compiler"] //Butterknife  plug-in (software component),很多人因 because of没加这个而报错,切记!!!
    annotationProcessor rootProject.ext.dependencies["dagger2-compiler"]// depend on plug-in (software component), annotationProcessor  be AndroidStudio 自带并用来替换 APT 
}

<a name="1.3.2"></a>

1.3.2 useLambda

of this framework Demo , default use Lambda , if you don't want to use Lambda perhaps use AndroidStudio v3.0 (兼容 java8), Please ignore以 under configure

  • In the project root directory of the Build.gradle 中 depend on Lambda Plugin
buildscript {
    repositories {
        jcenter()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:2.3.3'
        //lambda
        classpath 'me.tatarka:gradle-retrolambda:3.6.0'
    }
}
  • (located) at app of Build.gradle introducing in Lambda plug-in (software component)
apply plugin: 'me.tatarka.retrolambda'

android {

     compileOptions {//even if you're using AndroidStuido v3.0, you'll need to configure the following parameters
        targetCompatibility JavaVersion.VERSION_1_8
        sourceCompatibility JavaVersion.VERSION_1_8
    }
    
}

<a name="1.4"></a>

1.4 configure AndroidManifest

<a name="1.4.1"></a>

1.4.1 Adding Permissions

    <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"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE"/>
    <uses-permission android:name="android.permission.READ_PHONE_STATE"/>

<a name="1.4.2"></a>

1.4.2 Designation of Application

本框架想要正常运行 need use框架 offered BaseApplication , and of course you can customize a Application inherits from it, or it can be inherited without inheritance, and the BaseApplication to copy the code to your custom Application 里(里面只有几行代码),但 be我并不推荐你 use back面 of两种方式,因 because of本框架已经向开发者提供了 ConfigModule#injectAppLifecycle method, which can be used to dynamically add a new method to the BaseApplication into any code, so that even if you don't need to customize the Application , you can also do the initialization of your own business

<application
        android:name="com.jess.arms.base.BaseApplication"
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
</application>

<a name="1.4.3"></a>

1.4.3 configure Autolayout

use Autolayout adaptive框架必须 configure Meta 属性,即设计图 of宽高, particulars参考 Autolayout ,本框架并不强制你 use AutoLayout,如果你不想 use AutoLayout,就不要 configure下面 of meta-data

// configure设计图 of宽高,配合AutoLauout控件 use ,in设计图尺寸以外 of其它尺寸手机上,也能达到 harmony设计图一样 of效果
        <meta-data
            android:name="design_width"
            android:value="1080"/>
        <meta-data
            android:name="design_height"
            android:value="1920"/>

<a name="1.4.4"></a>

1.4.4 configure框架自定义属性

This framework uses andGlide相同 of方式来 configure自定义属性, need (located) atAndroidManifest Declare it in , particulars

<!--arms configure-->
        <meta-data
            android:name="me.jessyan.mvparms.demo.app.GlobalConfiguration"
            android:value="ConfigModule"/>

<a name="1.5"></a>

1.5 Confusion

Since the framework relies on a large number of three-party libraries, it has been implemented in arms Module under proguard-rules.pro The framework provides all the rules of the three-party library that the framework depends on, so if you want to use it, copy it and replace it with app Module hit the target proguard-rules.pro (Demo 并不能直接 use这个 proguard-rules.pro confusion), it is important to take care that the Java Bean , Customized Components etc.必需 of规则添加进 proguard-rules.pro

<a name="1.6"></a>

1.6 Version updates

  • For example, through Gradle Remote dependencies on this framework should be ignored

如果你获得 of this framework方式 be pass (a bill or inspection)clone perhaps者下载:

  1. 直接可以 pass (a bill or inspection)命令行git pull origin master拉取最新 of版本并自动合并
  2. If you change the package name you still have to execute the commandgit rm --cache -r app/src/main/java/me/jessyan/mvparms The next time you pull it, it won't be pulled.Demo content

如果你获得 of this framework方式 be pass (a bill or inspection)fork到自己 warehouse back,clone perhaps下载:

  1. git remote add arms https://github.com/JessYanCoding/MVPArms.git 添加远程 warehouse,arms be远程 warehouse of代号,可自定义,以 back都 pass (a bill or inspection)这个代号对远程 warehouse作操作
  2. git fetch arms拉取远程 warehouse最新 of版本
  3. git merge arms/master --allow-unrelated-histories Merge remote repository to current branch
  4. back面如果本框架有更新就只用重复2,3步,--allow-unrelated-histories Only use to add on the first merge
  5. If you change the package name you still have to execute the commandgit rm --cache -r app/src/main/java/me/jessyan/mvparms The next time you pull it, it won't be pulled.Demo content

<a name="2"></a>

2 Quick start

<a name="2.1"></a>

2.1 ConfigModule

ConfigModule 用来给框架 configure各种自定义属性 harmony功能,配合 GlobalConfigModule use非常强大

  • Create a new class that inherits from ConfigModule ,并 (located) at AndroidManifest state in
public class GlobalConfiguration implements ConfigModule {
    @Override
    public void applyOptions(Context context, GlobalConfigModule.Builder builder) {
      // Use builder to configure some configuration information for the framework
     builder.baseurl(Api.APP_DOMAIN)
            .cacheFile(New File("cache"));
    }

    @Override
    public void injectAppLifecycle(Context context, List<AppLifecycles> lifecycles) {
      // Inject some custom logic into the Application's lifecycle
    }

    @Override
    public void injectActivityLifecycle(Context context, List<Application.ActivityLifecycleCallbacks> lifecycles) {
     // Inject some custom logic into the Activity's lifecycle
    }

    @Override
    public void injectFragmentLifecycle(Context context, List<FragmentManager.FragmentLifecycleCallbacks> lifecycles) {
     // Inject some custom logic into the Fragment's lifecycle
}
}
<application>
     <!--arms configure-->
     <meta-data
         android:name="me.jessyan.mvparms.demo.app.GlobalConfiguration"
         android:value="ConfigModule"/>
</application>

<a name="2.2"></a>

2.2 AppComponent

Application生命周期 be harmonyApp be一样 of,所以适合提供一些单例对象,本框架 useDagger2 Management, useAppComponent in order to provide security situation all of单例对象,所以 need自定义一个Application inherited fromBaseApplication , which can be found in theApp of任何地方, pass (a bill or inspection)BaseApplication ofgetAppComponent() approach, get hold ofAppComponent里面声明 of all单例对象

@Singleton
@Component(modules = {AppModule.class, ClientModule.class, GlobalConfigModule.class})
public interface AppComponent {
    Application Application();

     // Used to manage the network request layer, as well as the data caching layer
    IRepositoryManager repositoryManager();

     //Rxjava error handling management class
    RxErrorHandler rxErrorHandler();


    OkHttpClient okHttpClient();

     // image manager, used to load the image management class, the default use glide, use the policy model, replaceable framework
    ImageLoader imageLoader();

    //gson
    Gson gson();

    //buffer memory documents根目录(RxCache harmonyGlide of ofbuffer memory都已经作 because of子 documents夹 (located) at这个目录里),应该将 allbuffer memory放到这个根目录里,便于管理 harmony清理,可 (located) atGlobeConfigModule里 configure
    File cacheFile();

    //用于管理 allactivity
    AppManager appManager();

    void inject(AppDelegate delegate);
}

<a name="2.3"></a>

2.3 RepositoryManager

RepositoryManager 用来管理网络请求层, and数据buffer memory层,以 back可能添加数据 warehouse请求层,专门提供给 Model 层做数据处理 ,in v1.5 版本前 be use ServiceManager harmony CacheManager 来管理 ,inv1.5 Use after version RepositoryManager replace

  • Self-defined Retrofit Service As follows, skilled Retrofit Please ignore
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);
}
  • Self-defined RxCache Provider As follows, skilled RxCache Please ignore
public interface CommonCache {

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

}
  • (located) at Model Passing in RepositoryManager#obtainRetrofitService() perhaps RepositoryManager#obtainCacheService() use这些服务
public Observable<List<User>> getUsers(int lastIdQueried, boolean update) {
        Observable<List<User>> users = mRepositoryManager.obtainRetrofitService(UserService.class)
                .getUsers(lastIdQueried, USERS_PER_PAGE);
        // userxcachebuffer memory, Pull-up refresh does not read the cache, Load More Read Cache
        return mRepositoryManager.obtainCacheService(CommonCache.class)
                .getUsers(users
                        , new DynamicKey(lastIdQueried)
                        , new EvictDynamicKey(update))
                .flatMap(new Func1<Reply<List<User>>, Observable<List<User>>>() {
                    @Override
                    public Observable<List<User>> call(Reply<List<User>> listReply) {
                        return Observable.just(listReply.getData());
                    }
                });
    }

<a name="2.4"></a>

2.4 MVP in action

Defining the business logicMVP , SuccessionMVP The respective base classes are sufficient, and can be defined slightly more coarsely hereMVP class, i.e., no need for eachFragment harmonyActivity (each page) defines a differentMVP class, you can use a set ofMVP kind

<a name="2.4.1"></a>

2.4.1 Contract

Here, according toGoogle formalMVP sports event,可以 (located) atContract defined inMVP interfaces,便于管理 ...this框架无需定义Presenter interface, soContract Define onlyModel harmonyView interfaces

public interface UserContract {
    //对于经常 use of关于UI of approach可以定义到IView Medium,如显示隐藏进度条, harmony显示文字消息
    interface View extends IView {
        void setAdapter(DefaultAdapter adapter);
        void startLoadMore();
        void endLoadMore();
    }
    //Model层定义接口,外部只需关心Model返回 of数据,无需关心内部细节,即 be否 usebuffer memory
    interface Model extends IModel{
        Observable<List<User>> getUsers(int lastIdQueried, boolean update);
    }
}

<a name="2.4.2"></a>

2.4.2 View

Generally let Activity perhaps Fragment realize Contract defined in of View Interface, for Presenter invoke对应 approach操作 UI , BaseActivity Default Injection Presenter , if you want to use Presenter , must be specified Presenter of范型(虽然只可以指定一个范型,但 be可以自行生成并持有多个 Presenter (for the purpose of reuse), and the implementation ofsetupActivityComponent in order to provide Presenter need of Component harmony Module(如这个页面逻辑简单并不 need Presenter ,那就不指定范型,也不 realize approach)

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

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

    }

    @Override
    public int initView(Bundle savedInstanceState) {
        return R.layout.activity_user;
    }

    @Override
    protected void initData() {

    }
}

<a name="2.4.3"></a>

2.4.3 Model

Model realize Contract of Model interface, and inherits from BaseModel , and then by IRepositoryManager Get what you need. Service harmony Cache because of Presenter 提供 need of数据( be否 usebuffer memory请自行选择)

@ActivityScope
public class UserModel extends BaseModel implements UserContract.Model{
    

     @Inject
    public UserModel(IRepositoryManager repositoryManager) {
        super(repositoryManager);
    }
    
    @Override
    public Observable<List<User>> getUsers(int lastIdQueried, boolean update) {
        mRepositoryManager.obtainRetrofitService(UserService.class)
                             .getUsers();
    }
  
}

<a name="2.4.4"></a>

2.4.4 Presenter

Presenter (located) atMVP hit the target大部分 of作用 because of pass (a bill or inspection)从Model层接口获取数据 ,in invokeView layer interface to display data, first implementingBasePresenter ,designatedModel harmonyView paradigm, note that you must specifyContract The interface defined in ,Presenter need ofModel harmonyView,都 useDagger2 Inject, so that it is easy to unroot and test, How do you inject it?

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

    @Inject
    public UserPresenter(UserContract.Model model, UserContract.View rootView) {
        super(model, rootView);
    }
     // Here the business methods are defined, corresponding to the user interaction
    public void requestUsers(final boolean pullToRefresh) {
    }
}

<a name="2.4.5"></a>

2.4.5 MVP Module

Here.Module Provides the current business logic corresponding to theView harmonyModel interface (Contract defined in interfaces) of realize kind,Model needAppComponent中 offeredRepositoryManager来 realize网络请求 harmonybuffer memory,所以 need pass (a bill or inspection)Component depend onAppComponent来 get hold of这个对象

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

     // When building the UserModule, pass in the View implementation class so that you can provide the View implementation class to the 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;
    }
}

<a name="2.4.6"></a>

2.4.6 MVP Component

The important thing to note here is that thisComponent Must rely onAppComponent , so as to provideModel need ofRepositoryManager , providing the inject() method will allow theModule andAppComponent中 offered对象注入到对应 of kind Medium,inject() hit the target参数不能 be接口, How do you inject it?

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

<a name="2.4.7"></a>

2.4.7 Dagger Scope

In the code above ActivityScope Appearing in large numbers in Module harmony Component Medium,Dagger2 use Scope Limit each Module The life cycle of the objects provided in , Dagger2 By default, only one @Singleton Scope 即单例, This framework provides @ActvityScope harmony @FragmentScope If you have any other requirements, please implement them yourself, Module harmony Component Define the same Scope back Module 中 offered对象 of生命周期会 harmony Component is bound to the lifecycle of (i.e., in Component 生命周期内,如需多次 use到 Moudle 中 offered对象,但只会 invoke一次@Provide 注解 of approach得到此对象)

<a name="2.4.8"></a>

2.4.8 MVP Summary

  • 以 back每个业务逻辑都重复构造这些 kind,只 be换个名字而已,值得注意 of beMVP刚开始用时确实会觉得平白无故多了很多 kind,非常繁琐麻烦,但 be etc.页面代码逻辑越来多时,你会发现其 hit the target好处,逻辑清晰,解耦,便于团队协作,测试容易,错误好定位,所以现 (located) at This framework providesTemplate Automatic code generation解决这个痛点,让开发者更加愉快 of use本框架

<a name="3"></a>

3 Use of functions

<a name="3.1"></a>

3.1 App security situation configure信息( useDagger注入)

GlobalConfigModule Use the builder mode to placeApp of security situation configure信息封装进Module( useDagger注入到 need configure信息 of地方),可以 configureCacheFile,Interceptor etc., evenRetrofit,Okhttp,RxCacheIt is all customizable, because the builder mode is used, so if you have additional configuration information to useDagger Inject, you can add directly to theBuilder And it won't affect the rest of the place

public class GlobalConfiguration implements ConfigModule {
    @Override
    public void applyOptions(Context context, GlobalConfigModule.Builder builder) {
      // Use builder to configure some configuration information for the framework
       builder.baseurl(Api.APP_DOMAIN)
              .gsonConfiguration((context12, gsonBuilder) -> {//这里可以自己自定义 configureGson of参数
                    gsonBuilder
                             .serializeNulls()// support for serializing null arguments
                             .enableComplexMapKeySerialization();//support will serialize the key for the map of object, the default can only serialize the key for the map of string
                })
                .retrofitConfiguration((context1, retrofitBuilder) -> {//这里可以自己自定义 configureRetrofit of参数,甚至你可以替换系统 configure好 ofokhttp对象
 // retrofitBuilder.addConverterFactory(FastJsonConverterFactory.create());// e.g. use fastjson instead of gson
                })
                .okhttpConfiguration((context1, okhttpBuilder) -> {//这里可以自己自定义 configureOkhttp of参数
                    okhttpBuilder.writeTimeout(10, TimeUnit.SECONDS);
                }).rxCacheConfiguration((context1, rxCacheBuilder) -> {//这里可以自己自定义 configureRxCache of参数
            rxCacheBuilder.useExpiredDataIfLoaderNotAvailable(true);
    }

}

<a name="3.2"></a>

3.2 security situation捕捉Http请求 harmony响应

(located) at security situation configure kind Passing inGlobalConfigModule.Builder.globalHttpHandler() approach transmitted inwardsGlobalHttpHandler

public class GlobalConfiguration implements ConfigModule {
    @Override
    public void applyOptions(Context context, GlobalConfigModule.Builder builder) {
        builder.globalHttpHandler(new GlobalHttpHandler() {// 这里可以提供一个 security situation处理Http请求 harmony响应结果 of处理 kind,
                    // 这里可以比客户端提前一步 get hold of服务器返回 of结果,可以做一些操作,比如token超时,重新获取
                    @Override
                    public Response onHttpResultResponse(String httpResult, Interceptor.Chain chain, Response response) {
                        /* 这里可以先客户端一步 get hold of每一次http请求 of结果,可以解析成json,做一些操作,如检测到token过期 back
                            Re-request the token and re-execute the request */
                        try {
                            if (!TextUtils.isEmpty(httpResult) && RequestInterceptor.isJson(response.body())) {
                                JSONArray array = new JSONArray(httpResult);
                                JSONObject object = (JSONObject) array.get(0);
                                String login = object.getString("login");
                                String avatar_url = object.getString("avatar_url");
                                Timber.w("Result ------> " + login + "    ||   Avatar_url------> " + avatar_url);
                            }

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


                      /* If you find that the token has expired, you can request the latest token first, and then put the new token in the request to re-request it
                        注意 (located) at这个回调之前已经 invoke过proceed,所以这里必须自己去建立网络请求,如 useokhttp use新 ofrequest去请求
                        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();
If you use okhttp to make a new request, after the request succeeds, you can return the response.
                        如果不 need返回新 of结果,则直接把response参数返回出去 */

                        return response;
                    }

                    // 这里可以 (located) at请求服务器之前可以 get hold ofrequest,做一些操作比如给request统一添加token perhaps者header and参数加密 etc.操作
                    @Override
                    public Request onHttpRequestBefore(Interceptor.Chain chain, Request request) {
                        /* 如果 need再请求服务器之前做一些操作,则重新返回一个做过操作 of ofrequeat如增加header,不做操作则直接返回request参数
                           return chain.request().newBuilder().header("token", tokenId)
                                  .build(); */
                        return request;
                    }
                });
    }
}

<a name="3.3"></a>

3.3 security situation错误处理 and发生错误时重新执行

If you need to useRxjava of security situation错误处理,需 (located) at security situation configure kind Passing inGlobalConfigModule.Builder.responseErroListener() approach transmitted inwardsResponseErroListener , and to use it every timeRxjava invokesubscribe时, useErrorHandleSubscriber , and pass it inAppComponent中 offeredRxErrorHandler ...thisSubscribe , already implemented by defaultOnError method, you can override it if you want to customize it.OnError approach

public class GlobalConfiguration implements ConfigModule {
    @Override
    public void applyOptions(Context context, GlobalConfigModule.Builder builder) {
        builder.responseErrorListener((context1, e) -> {
                    /* 用 in order to provide处理 all错误 of监听
                        rxjava requires the use of ErrorHandleSubscriber (which implements the onError method of the Subscriber by default) for this listener to take effect */
                    Timber.w("------------>" + e.getMessage());
                    ArmsUtils.SnackbarText("net error");
                });
    }
}
  • (located) atRxjava中 use
Observable
.just(1)
 .retryWhen(new RetryWithDelay(3,2))//retry when an error is encountered, the first parameter is the number of retries, the second parameter is the retry interval
.subscribe(new ErrorHandleSubscriber<Integer>(mErrorHandler) {
     @Override
     public void onNext(Integer Integer) {
 
     }
});

<a name="3.4"></a>

3.4 ImageLoader How to extend and switch the image request framework

The framework defaults to using the Glide Implement the image loading function, using ImageLoader 提供统一 interfaces, ImageLoader Using the policy and builder patterns, you can dynamically switch between image request frameworks (for example, switching to Picasso ),并且加载图片时 transmitted inwards of参数也可以随意扩展( loadImage approach (located) at need扩展参数时, invoke端也不 need改动,全部 pass (a bill or inspection) Builder 扩展,比如你想让内部 of图片加载框架,清除buffer memory你只 need定义个 boolean 字段,内部根据这个字段 if|else,其他操作同理,当 need切换图片请求框架 perhaps图片请求框架升级 back变更了 Api In the case of the "D", the impact range can be minimized here, so the package ImageLoader be because of了屏蔽这个风险)

  • ! The framework provides by default GlideImageLoaderStrategy harmony ImageConfigImpl simple implementation of the image loading logic , easy to use quickly , but the development will inevitably encounter complex use of the scenario , so the framework is recommended even if you do not switch the image request framework continue to use Glide Please also implement your own image loading policy as described below, because the default implementation of GlideImageLoaderStrategy is packaged directly into the framework, if it is a remote dependency, you will not be able to extend the logic inside when you encounter a situation that does not meet the requirements
  • use ImageLoader You must pass in a file that implements the BaseImageLoaderStrategy 接口 of图片加载 realize kind从而 realize动态切换,所以首先要 realizeBaseImageLoaderStrategy , realize时必须指定一个 inherited from ImageConfig of realize kind, use建造者模式,可以储存一些信息,比如 URL , ImageView , Placeholder etc.,可以不断 of扩展,供图片加载框架 use
public class PicassoImageLoaderStrategy implements BaseImageLoaderStrategy<PicassoImageConfig> {
     @Override
    public void loadImage(Context ctx, PicassoImageConfig config) {
                        Picasso.with(ctx)
                .load(config.getUrl())
                .into(config.getImageView());
    }
}
  • realize ImageCofig Using the builder pattern (creating a new PicassoImageConfig 适用于新 sports event,如果想重构之前 of sports event, use其他图片加载框架, because of了避免影响之前 of代码,请继续 use默认 offered ImageConfigImpl Or your previous self-implemented ImageConfig ,并可继续扩展里面 of属性)
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);
        }
    }
}
  • (located) at App Just started initialization via GlobalConfigModule Pass in the above extended PicassoImageLoaderStrategy , also available in App During operation by AppComponent get hold of ImageLoader After the object, setLoadImgStrategy(new PicassoImageLoaderStrategy) 替换之前 of realize(默认 use Glide)
 Method I:  pass (a bill or inspection)GlobalConfigModule transmitted inwards
public class GlobalConfiguration implements ConfigModule {
    @Override
    public void applyOptions(Context context, GlobalConfigModule.Builder builder) {
        builder.imageLoaderStrategy(new PicassoImageLoaderStrategy);
    }
}

 Method II:  get hold ofAppComponent hit the target ImageLoader, Pass in the method
mApplication
    .getAppComponent()
    .imageLoader()
    .setLoadImgStrategy(new PicassoImageLoaderStrategy());


 use approach

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

<a name="3.5"></a>

3.5 AndroidEventBus Tag

本框架 use AndroidEventBus realize事件总线 ...this框架 use注解标记目标 approach,统一将 Tag The constants written to the EventBusTag 接口 Medium,便于管理,如果要 (located) at当前对象中 use AndroidEventBus 请 (located) at need use of Activity , Fragment , Presenter rewrite in useEventBus() ,return true means use, default returns true Why? MVPArms use AndroidEventBus 而不 be greenrobot of EventBus See here. My answer.

<a name="3.6"></a>

3.6 AutoLayout components

本框架 useAutoLayout framework to implement control adaption, this framework to make the component adaptive, you must make its parent control, re-measure, and rewriteLayoutParams , while only three are officially provided by defaultViewGroup,AutoRelativeLayout,AutoLinearLayout,AutoFrameLayout implements these operations , in order to facilitate the use of developers , the framework provides some commonAutoLayout组件 ,in框架 ofwidget charteredautolayout In the package, in thexmlThe child control can be made adaptive by referencing it in the Template (at the end) If you need to make a ScrollView's child controls adaptive, use this Template to input a ScrollView to generate an AutoScrollView.xml Just quote it in

<a name="3.7"></a>

3.7 Customizing PopupWindow

The framework provides a customizable builder pattern using PopupWindow Components: CustomPopupWindow , you can use this class directly after implementing the layout yourself PopupWindow , use builder mode, extend custom parameters at will

<a name="3.8"></a>

3.8 Quick implementation of RecycleView

This framework providesDefaultAdapter harmonyBaseHolder基 kind快速 realizeRecycleview.

  • BaseHolder Initialized by defaultButterKnife harmonyAutoLayout , the inheritance not only allows direct injection ofView,布局还可以 adaptive屏幕
  • RecycleView默认 be不提供Item of the click event of, useDefaultAdapter invokesetOnItemClickListener It is possible to achieveItem of the click event

<a name="3.9"></a>

3.9 Permissions Management (Adapted to Android 6.0 Permissions Management)

本框架 useRxPermissions For permission management (for android 6.0), and provide PermissionUtil tool class one line of code to achieve permission request. Adapting to Android 6.0 Permission Management Explained

PermissionUtil.launchCamera(new PermissionUtil.RequestPermission() {
            @Override
            public void onRequestPermissionSuccess() {
                launchCapture();// Do some actions after requesting permission successfully
            }
            
            @Override
            public void onRequestPermissionFailure() {
                mRootView.showMessage("Request permissons failure");
            }

        }, mRxPermissions, mErrorHandler);

<a name="3.10"></a>

3.10 Gradle configure启动DeBug模式

(located) at主 sports event(app) ofbuild.gradle中 configure be否开启打印Log perhaps则 be否 useLeakCanary , and other debugging tools

  • (located) atbuild.gradle中 configure
android {

    buildTypes {

        debug {
        //这两个变量 be自定义 of,自己也可以自定义字段,他会默认 configure到BuildConfig Medium,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'
        }
    }
  • Use it in code (e.g. in App Do some initialization settings when initializing)
@Override
    public void injectAppLifecycle(Context context, List<AppLifecycles> lifecycles) {
        lifecycles.add(new AppLifecycles() {
      
            @Override
            public void onCreate(Application application) {
                 if (BuildConfig.LOG_DEBUG) {//Timber log printing
                    Timber.plant(new Timber.DebugTree());
                }
        if (BuildConfig.USE_CANARY) {//leakCanary Memory leak check
                    LeakCanary.install(this);
                }
            }
        });
    }

<a name="3.11"></a>

3.11 AppManager(管理 all ofActivity)

AppManager This is used to manage all Activities, and holds an internal list of all live Activities (without calling onDestroy), and one Activity that is currently at the top (without calling onPause),AppManager封装有多种 approach,可以很方便 of对它们进行操作 , also available in未持有AppManager In the case of theEventBus远程遥控它 of all approach,这样我们可以 (located) at整个app Any global operation on any Activity anywhere in theapp请求网络超时时让最前端 ofActivity显示连接超时 of交互页面(这个逻辑不用写到当前请求 ofActivity里,可以 (located) at一个单例 kind里做 security situation of统一操作,因 because of可以随时 pass (a bill or inspection)AppManager get hold of当前 ofActivity)

  • 远程遥控 pass (a bill or inspection) AppManager.post(Message) Achieved, through Message The different what Distinguish between different methods and Handler Similarly, it can be expanded according to your needs.
  • How do you expand your needs? (located) at ConfigModule#injectAppLifecycle(Context, List) Passing in AppLifecycles#onCreate(Application) ,in App 初始化时, configure满足自己需求 of HandleListener
   @Override
    public void injectAppLifecycle(Context context, List<AppLifecycles> lifecycles) {
        lifecycles.add(new AppLifecycles() {
      
            @Override
            public void onCreate(Application application) {
                ArmsUtils.obtainAppComponentFromContext(application).appManager().setHandleListener(new AppManager.HandleListener() {
                    @Override
                    public void handleMessage(AppManager appManager, Message message) {
                        switch (message.what) {
                            //case 0:
                            //do something ...
                            //   break;
                        }
                    }
                });
            }
        });
    }
  • 如何 use? pass (a bill or inspection) AppManager.post(Message) 发送不同 what of Message The object can be
   Message msg = new Message();
   msg.what = 0;
   AppManager.post(msg); //like EventBus

<a name="3.12"></a>

3.12 AppDelegate (proxy Application life cycle)

AppDelegate Can represent Application The life cycle, in the corresponding life cycle, to execute the corresponding logic, because Java 只能单继承,所以当遇到某些三方 warehouse need继承于它 of Application When the only customization is Application and inherited from the tripartite library of Application , at which point there is no need to inherit BaseApplication,只用 (located) at自定义 Application The corresponding lifecycle call in AppDelegate Corresponding methods (Application Must be achieved APP interface), the framework will work as usual, and Application The corresponding life cycle in can be extended using

public class GlobalConfiguration implements ConfigModule {

@Override
    public void injectAppLifecycle(Context context, List<AppLifecycles> lifecycles) {
         // All methods of AppLifecycles will be called in the corresponding lifecycle of the base class Application, so you can extend the logic you need in the corresponding methods
        lifecycles.add(new AppLifecycles() {
             private RefWatcher mRefWatcher;//leakCanary watcher

            @Override
            public void onCreate(Application application) {
                 if (BuildConfig.LOG_DEBUG) {//Timber log printing
                    Timber.plant(new Timber.DebugTree());
                }
                 //leakCanary memory leak check
                this.mRefWatcher = BuildConfig.USE_CANARY ? LeakCanary.install(application) : RefWatcher.DISABLED;
            }

            @Override
            public void onTerminate(Application application) {
                this.mRefWatcher = null;
            }
        });
    }

}

<a name="3.13"></a>

3.13 ActivityDelegate harmony FragmentDelegate

The idea implemented here is so awesome, so please see what I wrote essay

<a name="3.14"></a>

3.14 框架中 RxLifecycle of use

Refer here


Recommended>>
1、Yuan Ye Nothing to do with blockchain Blockchain Thinking Block 17
2、Unmanned cars can get out and about in Shanghai The driver said he could let go almost the entire time
3、Software Engineering National Big Data Analytics
4、IBM Chief Data Officer How Effective Data Science Teams Are Built
5、ZCASH the ASIC miner is finally here

    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号