Android开源组件化开发框架Android-Sun-Framework
xiongrq
7年前
<h2>一. 写在前面</h2> <p>Android-Sun-Framework是一个Android组件化开发框架,可用于中大型项目。</p> <h2>二. 框架结构</h2> <p>遵循高内聚低耦合理念,Module之间没有强依赖,具体结构如下图:</p> <p style="text-align:center"><img src="https://simg.open-open.com/show/6fd1e0e037a77d373264f7b8cfab2be7.png"></p> <h2>三. 框架依赖</h2> <pre> <code class="language-java">//Rx系列 compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'com.trello.rxlifecycle2:rxlifecycle:2.0.1' compile 'com.trello.rxlifecycle2:rxlifecycle-android:2.0.1' compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.0.1' //Retrofit compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0' //路由 compile 'com.github.mzule.activityrouter:activityrouter:1.2.2' //图片加载 compile 'com.github.bumptech.glide:glide:3.7.0' //下拉刷新 compile 'com.lcodecorex:tkrefreshlayout:1.0.7' compile 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.15'</code></pre> <h2>三. 详细说明</h2> <p>下面我会根据代码,详细讲解框架结构及其使用说明。</p> <h3>A. 配置中心config.gradle</h3> <pre> <code class="language-java">ext { android = [ compileSdkVersion: 25, buildToolsVersion: "25.0.2", minSdkVersion : 19, targetSdkVersion : 25, versionCode : 1, versionName : "1.0.0", isModule : false, //是否是独立模块开发 isDebug : "true",//是否是调试模式 scheme : "\"xpai\"" //应用scheme ] //依赖配置 dependencies = [ "supportVersion": "25.2.0" ] }</code></pre> <p>当前配置项还不多,后面会根据实际开发需要,优化配置。</p> <p>这里我单独说明一下isModule的作用:</p> <ol> <li>当isModule为真时,除了library子模块为library,其他子模块均为application,我们以login模块为例,看一下是如何实现的</li> </ol> <pre> <code class="language-java">if (rootProject.ext.android.isModule) { apply plugin: 'com.android.application' } else { apply plugin: 'com.android.library' } android { compileSdkVersion rootProject.ext.android.compileSdkVersion buildToolsVersion rootProject.ext.android.buildToolsVersion defaultConfig { if (rootProject.ext.android.isModule) { applicationId "com.ody.login" } 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' } } sourceSets { main { if (rootProject.ext.android.isModule) { manifest.srcFile 'src/main/debug/AndroidManifest.xml' } else { manifest.srcFile 'src/main/AndroidManifest.xml' //release模式下排除debug文件夹中的所有Java文件 java { exclude 'debug/**' } } } } } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') annotationProcessor 'com.github.mzule.activityrouter:compiler:1.1.7' compile project(':library') }</code></pre> <p>我们主要看一下rootProject.ext.android.isModule的if判断,这里根据它来配置当前模块plugin为library还是application。当为application时,下面会增加applicationId的配置。</p> <p>仔细的同学可能会问,sourceSets的配置是干嘛的?由于application 必须要有默认启动Activity,所以这里我们需要根据isModule使用不同的AndroidManifest.xml,每个模块可能会有测试代码,所以只要把测试代码写在debug包下面,正式编译的时候debug下面的java文件不会参与编译。</p> <p>同样的我们来看一下主Module的配置:</p> <pre> <code class="language-java">apply plugin: 'com.android.application' android { ...... } dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') testCompile 'junit:junit:4.12' //路由 annotationProcessor 'com.github.mzule.activityrouter:compiler:1.1.7' if (rootProject.ext.android.isModule) { compile project(':library') } if (!rootProject.ext.android.isModule) { compile project(':guide') } if (!rootProject.ext.android.isModule) { compile project(':login') } if (!rootProject.ext.android.isModule) { compile project(':trade') } if (!rootProject.ext.android.isModule) { compile project(':usercenter') } }</code></pre> <p>这里我们只关注dependencies,根据isModule来配置是否依赖该Module.</p> <ol> <li>当isModule为真时,Module可以单独运行,这样做的好处是:一:大大缩减编译时间;二:可以跨部门,跨团队协作。 <h3>B. Module间跳转</h3> 对比 ARouter 与 ActivityRouter ,我决定使用ActivityRouter,主要原因有两个:</li> <li>由于ARouter加入分组概念,和我们公司当前已有设计相违背;</li> <li>ActivityRouter比ARouter精简,后面我会分享一下ActivityRouter和ARouter的实现原理, <strong>敬请期待!</strong></li> </ol> <p>ActivityRouter具体如何使用我就不再赘述,详细可以查看 ActivityRouter ,里面有详细的说明和demo。我在这里要强调一下ActivityRouter多模块需要如何实现?</p> <p>实现步骤:</p> <p>a. 在子Module中新建一个Module类,比如我这里的login模块:</p> <pre> <code class="language-java">@Module("login") public class LoginModule { }</code></pre> <p>b. 同样在主Module中也需要新建一个类</p> <pre> <code class="language-java">@Module("app") public class AppModule { }</code></pre> <p>c. Module注册</p> <pre> <code class="language-java">@Modules({"app", "login"}) public class OdyApplication extends BaseApplication { }</code></pre> <p>d. 界面跳转</p> <p>为了能统一处理,自己把ActivityRouter的跳转封装了一层:</p> <pre> <code class="language-java">public class JumpUtils { public final static String LOGIN_URL = "login"; public static void open(Context context, String url) { Routers.open(context, BuildConfig.SCHEME + "://" + url); } public static void open(Context context, String url, RouterCallback callback) { Routers.open(context, BuildConfig.SCHEME + "://" + url, callback); } }</code></pre> <p>JumpUtils里的常量就是跳转注解路径</p> <pre> <code class="language-java">@Router(JumpUtils.LOGIN_URL) public class LoginActivity extends BaseActivity { ...... }</code></pre> <p>以上都是为了能更好的 <strong>统一管理,避免后期修改多处</strong> 。</p> <h3>C. 网络库封装</h3> <p>做Android开发的想必大家都知道Retrofit和Rxjava,我们也是使用的他们,为了更好的控制网络请求,这里我同时引入了Rxlifecycle。接下来我们看看具体是如何实现的</p> <ol> <li>添加依赖</li> </ol> <pre> <code class="language-java">//Rx系列 compile 'io.reactivex.rxjava2:rxandroid:2.0.1' compile 'com.trello.rxlifecycle2:rxlifecycle:2.0.1' compile 'com.trello.rxlifecycle2:rxlifecycle-android:2.0.1' compile 'com.trello.rxlifecycle2:rxlifecycle-components:2.0.1' //Retrofit compile 'com.squareup.retrofit2:retrofit:2.1.0' compile 'com.squareup.retrofit2:converter-gson:2.1.0' compile 'com.squareup.retrofit2:adapter-rxjava2:2.2.0'</code></pre> <ol> <li>Retrofit接口定义</li> </ol> <pre> <code class="language-java">public interface BaseNetApi { @GET("/api/dolphin/list?&platform=3&platformId=0&pageCode=APP_HOME&adCode=ad_banner&areaCode=310115") Observable<AdBean> getAd(@QueryMap Map<String, String> params); }</code></pre> <ol> <li>Retrofit初始化和具体实现</li> </ol> <pre> <code class="language-java">public class SingletonNet { public static final String BASE_URL = "http://api.laiyifen.com"; private static final int DEFAULT_TIMEOUT = 30; private Retrofit retrofit; private volatile static SingletonNet INSTANCE = null; private SingletonNet() { //手动创建一个OkHttpClient并设置超时时间 OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder //添加公共header .addInterceptor(new Interceptor() { @Override public Response intercept(Chain chain) throws IOException { Request.Builder builder = chain.request().newBuilder(); builder.addHeader("token", "123"); return chain.proceed(builder.build()); } }) .connectTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS) .readTimeout(DEFAULT_TIMEOUT, TimeUnit.SECONDS); Retrofit.Builder b = new Retrofit.Builder() .client(builder.build()) .addConverterFactory(GsonConverterFactory.create()) .addCallAdapterFactory(RxJava2CallAdapterFactory.create()) .baseUrl(BASE_URL); retrofit = b.build(); } public static SingletonNet getSingleton() { if (INSTANCE == null) { synchronized (SingletonNet.class) { if (INSTANCE == null) { INSTANCE = new SingletonNet(); } } } return INSTANCE; } public <T> T getNetService(Class<T> t) { return retrofit.create(t); } }</code></pre> <p>我们使用泛型,为各个模块创建自己的API,这样做能更好的解耦。同时我们也在基础库里实现了BaseNetApi,这里是项目中重复使用的接口,避免多处实现同一个接口。我们再来看一下其他Module里是如何创建的</p> <pre> <code class="language-java">public class MainHttpClient extends BaseHttpClient { private static class SingletonHolder { private static final MainApi API = SingletonNet.getSingleton().getNetService(MainApi.class); } public static Observable<AdBean> get() { Map<String, String> params = new HashMap<>(); return SingletonHolder.API.get(params); } }</code></pre> <p>这里采用静态内部类实现了单例,和SingletonNet的单例有区别。</p> <ol> <li>具体使用</li> </ol> <pre> <code class="language-java">MainHttpClient.get() .compose(RxSchedulers.<AdBean>compose()) .compose(this.<AdBean>bindToLifecycle()) .subscribe(new HttpObserver<AdBean>(mContext) { @Override protected void success(AdBean bean) { super.success(bean); } });</code></pre> <p>.compose(RxSchedulers.<AdBean>compose())线程调度等重复操作放在这里;</p> <p>.compose(this.<AdBean>bindToLifecycle()) 网络请求和Activity生命周期想关联。</p> <p>HttpObserver的实现如下:</p> <pre> <code class="language-java">public abstract class HttpObserver<T> implements Observer<T> { private Context mContext; protected HttpObserver(Context context) { mContext = context.getApplicationContext(); } @Override public final void onSubscribe(Disposable d) { } @Override public final void onNext(T value) { success(value); } @Override public final void onError(Throwable e) { error(e.toString()); } @Override public final void onComplete() { complete(); } protected void success(T t) { } protected void error(String msg) { } protected void complete() { } }</code></pre> <p>final是为了避免用户重写,强制重写后面自定义的几个方法。</p> <h2>TOTO</h2> <ol> <li>引入dagger2</li> <li>开启混淆</li> <li>分享基础库</li> <li>图片选择</li> <li>下拉刷新</li> <li>轮播</li> <li>客服</li> <li>推送</li> </ol> <p> </p> <p>项目主页:<a href="http://www.open-open.com/lib/view/home/1494400907579">http://www.open-open.com/lib/view/home/1494400907579</a></p> <p> </p>