导言:千里之行,始于足下。

如果你从事Android开发,请仔细看完本篇文章,因为可能会推翻你对Android开发的知道。

当夜空中繁星点点,一颗璀璨的流星划过,其辉光洒在陈旧的山沟之中,照亮了一个隐藏在山石之间的窟窿。

窟窿内的空气弥漫着奥秘的气息,流星划过的光辉越来越亮,窟窿内的温度也开端升高。你能感遭到一股无法言喻的力气,这似乎是一个新的时代的开端。

忽然,窟窿内的石壁开端宣布耀眼的光辉,似乎有某种能量觉醒了。你不禁一愣,然后意识到这是传说中的创世神器正在诞生。

在光辉中,一块巨大的水晶开端从石壁上升起,悬浮在空中,它便是github.com/dora4/dora 。这块水晶透射出五彩斑斓的光辉,你能感觉到其间包含的无限力气。你走近一看,石壁上镌刻着一行行整齐的铭文,原来是github.com/dora4/dora_… 。你忽然意识到,这石壁上的铭文似乎跟眼前这块巨大的水晶存在着某种密不可分的联络。莫非上面镌刻着这块水晶的运用办法?你思索着。

石壁最初写着这么几行文字。

这块水晶散发着弱小但持续的吸引力,它能够用来吸引其他美丽的宝石,并使其绕着自己旋转,并释放出洪亮动人的歌声。以某种办法,能够让其吸附到水晶上,并获取其能力。 比方:

implementation("com.github.dora4:dora:1.1.37")
implementation("com.github.dora4:dora-firebase-support:1.2")
implementation("com.github.dora4:dora-glide-support:1.2")
implementation("com.github.dora4:dora-arouter-support:1.6")

你似乎对眼前的事物非常感兴趣,然后读起了正文。

正文

项目从模块化、组件化开端

在Android开发中,模块化、组件化是一个重要的论题。因为,它能够从事务产品层面解耦合,并不仅仅是单一模块的代码。这样做有什么好处呢?它能够从认知层面杜绝中心代码泄露给潜在的竞争对手。非中心模块单独也能运行,一起也能够运行在宿主程序中,作为主程序的一个模块进行打包。这样的项目结构大概是app模块、根底库模块、公共代码库模块以及一个个的事务模块。

那么app模块里边只放一个Application,清单文件里边只装备一个进口activity和公共的权限以及引用到的app名称和logo资源等。然后将该进口activity从其地点模块的清单文件中注释掉。留意,这个进口也是能够换的。

根底库,便是dora全家桶结构所要做的事情。比方dora中心架构库github.com/dora4/dora 及其扩展包,比方github.com/dora4/dora-… glide图片加载扩展包、github.com/dora4/dora-… arouter模块化、组件化扩展包以及github.com/dora4/dcach… dcache网络恳求与数据持久化库等。这些根底库是一切模块都可能用到的。所以我们在公共代码库里边去implementation这些根底库。最终其他一切事务相关的模块都直接compileOnly这个公共代码库和其需求的功能型开源库。最终app模块implementation你一切要打包进来的模块,当然也包括公共代码库。因为dora的这些support扩展包大多是运用api依靠的这些第三方SDK,而不是运用的implementation,所以你能够直接穿透运用第三方SDK的API办法。这样相当于直接获取了第三方SDK的功能,一起也能运用support包的一些优化API。

公共代码库,里边放一切事务模块的model、api接口、以及自界说View等,也包含一切通用的资源文件,包括但不仅限于strings.xml、colors.xml以及drawable等。重要的事情便是ARouter的一切途径一定要放在公共代码库,这样你一切依靠公共代码库的模块都能够经过这个途径花名册调用到其他任何一个模块的任意一个功能。当然这个是运用了ARouter的IProvider接口配合@Autowired注解进行依靠注入运用的。

更高效和舒服的开发办法,MVVM

MVVM,即Model-View-ViewModel开发模式。model指你的数据,你的模型或实体类,view则表明一切承载界面的容器activity、fragment、dialog等以及其上面的contentView,viewmodel是model跟view的中间层,因为model跟view不直接树立联络。

此物一出天下反,Dora犹如优秀框架的粘合剂

Android中的MVVM首要运用的是Jetpack中的一些开发套件。比方DataBinding、BindingAdapter、LiveData、ViewModel、ObservableField、Lifecycle等。 举个比如:我们能够在xml中界说一些变量,在view层去绑定这些变量。

<layout>
    <data>
        <variable
            name="v"
            type="com.example.dora.MenuListActivity" />
        <variable
            name="vm"
            type="com.example.dora.vm.VMMenu" />
    </data>
    <!-- 以下是你的contentView布局 -->
    <RelativeLayout>...</RelativeLayout>
</layout>

然后在view层的kotlin或java代码给这些xml中界说的变量赋值。

override fun initData(savedInstanceState: Bundle?, binding: ActivityMenuListBinding) {
    binding.v = this
    binding.vm = ViewModelProvider(this)[VMMenu::class.java]
}
运用BindingAdapter扩展控件特点完成点击事情
class BindingAdapters {
    companion object {
        @JvmStatic
        @BindingAdapter("android:click")
        fun bindClick(view: View, listener: OnClickListener) {
            view.setOnClickListener(listener)
        }
    }
}

这样你就能够在xml中的控件中运用android:click特点,并指定一个lambda表达式来快捷绑定点击事情了。

<Button
    android:id="@+id/btn_next_page"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_marginBottom="50dp"
    android:layout_gravity="bottom|center_horizontal"
    android:text="下一页"
    android:click="@{()->v.nextPage()}"/>

这个nextPage()办法界说在view层,如activity中。因为nextPage()办法是dora结构中dora.BaseActivity的API,所以无需界说,直接运用。

这儿需求留意的是装备了@BindingAdapter的办法必须是static办法,如果是kotlin,则必须加上@JvmStatic注解,否则无法绑定成功。

运用BindingAdapter绑定RecyclerView的BaseQuickAdapter适配器

在BindingAdapters.kt中增加以下办法。

@JvmStatic
@BindingAdapter("android:adapter")
fun <T, B : ViewDataBinding> bindAdapter(recyclerView: RecyclerView, adapter: BaseAdapter<T, B>) {
    recyclerView.adapter = adapter
}
@JvmStatic
@BindingAdapter("android:itemDecoration")
fun bindItemDecoration(recyclerView: RecyclerView, decoration: ItemDecoration) {
    recyclerView.addItemDecoration(decoration)
}

然后就能够在xml中的RecyclerView控件中指定这些特点了。

<androidx.recyclerview.widget.RecyclerView
    android:id="@+id/rv_menu_list"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
    android:itemDecoration="@{vm.listDecorationObservable}"
    android:adapter="@{vm.adapterObservable}"/>

诶,你有没有发现,这儿指定的是ViewModel里边的ObservableField系列特点。

package com.example.dora.vm
import androidx.databinding.ObservableField
import androidx.lifecycle.ViewModel
import androidx.recyclerview.widget.DividerItemDecoration
import com.example.dora.BaseAdapter
import dora.util.GlobalContext
open class BaseViewModel : ViewModel() {
    var listDecorationObservable = ObservableField<DividerItemDecoration>()
    var adapterObservable = ObservableField<BaseAdapter<*,*>>()
    init {
        listDecorationObservable.set(DividerItemDecoration(GlobalContext.get(), DividerItemDecoration.VERTICAL))
    }
}

这便是viewmodel+observablefield的一种开发办法,observablefield里边的值发生变化,UI会主动更新。还有别的一个开发办法则是viewmodel+livedata。

ViewModel的作用

运用viewmodel最大的好处便是便利复用,viewmodel里边的数据因为它源码中是保存在hashmap中的,所以你能够了解成内存缓存,你能够在横竖屏切换以及多个界面中复用这部分数据,而无需从头恳求。乃至一些通用的数据你能够直接放在BaseViewModel中,这样你只要承继BaseViewModel,就能够直接在xml中运用这些数据了。运用viewmodel和databinding还有一个好处便是便利在xml和kotlin/java代码中进行切换阅览代码,直接点过去就能够找到详细的某个当地了。是不是瞬间就减少了我们找代码的时刻?

Dora SDK的大局装备GlobalConfig原了解析

下面重点讲解一下GlobalConfig这个东西。很多第三方SDK都是要初始化的,所以这也是Dora SDK的一个强大用处。经过装备文件注入第三方SDK的生命周期完成。

<application>
    <meta-data
        android:name="dora.lifecycle.config.TaskStackGlobalConfig"
        android:value="GlobalConfig" />
    <meta-data
        android:name="dora.lifecycle.config.ARouterGlobalConfig"
        android:value="GlobalConfig" />
    <meta-data
        android:name="dora.lifecycle.config.EventBusGlobalConfig"
        android:value="GlobalConfig" />
</application>

你经过在AndroidManifest.xml清单文件的application节点下装备meta-data元数据,来直接注入大局的生命周期。android:name指定config的完成类的全类名,android:value指定GlobalConfig。这样Dora SDK就能够经过解析xml来读取这些装备,并直接在大局的生命周期中注入这些装备了。

在AppDelegate里边有一个DefaultGlobalConfig,这儿给你供给了一个完成GlobalConfig类的模板。结构层最终会逐一解析这些GlobalConfig并在生命周期中对这些代码进行叠加。

private static class DefaultGlobalConfig implements GlobalConfig {
    @Override
    public void injectApplicationLifecycle(Context context, List<ApplicationLifecycleCallbacks> lifecycles) {
        // All methods in AppLifecycle will be called during the corresponding lifecycle of
        // the base Application class,
        // so you can extend your own logic in the respective methods.
        // Multiple implementation classes can be added based on different logic requirements.
        // 简体中文:AppLifecycle 中的一切办法都会在基类 Application 的对应生命周期中被调用, 所以在对应的方
        // 法中能够扩展一些自己需求的逻辑
        // 能够依据不同的逻辑增加多个完成类
        lifecycles.add(new AppLifecycle());
    }
    @Override
    public void injectActivityLifecycle(Context context, List<Application.ActivityLifecycleCallbacks> lifecycles) {
        // All methods in ActivityLifecycleCallbacks will be called during the corresponding
        // lifecycle of the Activity (including third-party libraries),
        // so you can extend your own logic in the respective methods.
        // Multiple implementation classes can be added based on different logic requirements.
        // 简体中文:ActivityLifecycleCallbacks 中的一切办法都会在 Activity (包括三方库) 的对应生命周期中
        // 被调用,所以在对应的办法中能够扩展一些自己需求的逻辑
        // 能够依据不同的逻辑增加多个完成类
        lifecycles.add(new ActivityLifecycle());
    }
    @Override
    public void injectFragmentLifecycle(Context context, List<FragmentManager.FragmentLifecycleCallbacks> lifecycles) {
        // All methods in FragmentLifecycleCallbacks will be called during the corresponding
        // lifecycle of the Fragment (including third-party libraries),
        // so you can extend your own logic in the respective methods.
        // Multiple implementation classes can be added based on different logic requirements.
        // 简体中文:FragmentLifecycleCallbacks 中的一切办法都会在 Fragment (包括三方库) 的对应生命周期中
        // 被调用,所以在对应的办法中能够扩展一些自己需求的逻辑
        // 能够依据不同的逻辑增加多个完成类
        lifecycles.add(new FragmentLifecycle());
    }
}

大多数dora的扩展包support库都会给你供给引荐的默许装备,你能够直接装备到你的清单文件中。暂时是手动操控装备到开关,并非implementation库即装备。这样做的意图便是你能够在调试的时分,仅注释掉装备,而无需从头索引和更新一切依靠。

装备解析的关键代码如下,默许装备主动被增加进去,一起解析其他一切GlobalConfig的生命周期注入装备,如application的生命周期、activity的生命周期。

public AppDelegate(Context context) {
    this.mConfigs = ManifestParser.parse(context);
    this.mConfigs.add(0, new DefaultGlobalConfig());
    for (GlobalConfig config : mConfigs) {
        config.injectApplicationLifecycle(context, mApplicationLifecycles);
        config.injectActivityLifecycle(context, mActivityLifecycles);
    }
}

别的fragment的生命周期则是作为activity的子项注入。

@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
    registerFragmentCallbacks(activity);
}

运用Android Studio IDE插件来提高开发功率

你还能够运用IDE插件来快速创立BaseAcitivityBaseFragment

此物一出天下反,Dora犹如优秀框架的粘合剂

此物一出天下反,Dora犹如优秀框架的粘合剂

插件项目:github.com/dora4/dora-…

插件包:dorachat.oss-cn-hongkong.aliyuncs.com/dora-studio…

后记

你看完了铭文,顿时茅塞顿开,发现这么好的东西决不能落到坏人手里。决定拿着这颗奇特的水晶去除恶扬善,解救天下苍生,将这种能量传达出去。从此你获得了令人羡慕的成果、夸姣的爱情、无尽的愉悦、享不尽的荣华富贵,过上了幸福的生活。