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

news2024/12/23 22:25:20

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

如果你从事Android开发,请认真看完本篇文章,因为可能会颠覆你对Android开发的认识。

当夜空中繁星点点,一颗璀璨的流星划过,其辉光洒在古老的山谷之中,照亮了一个隐藏在山石之间的洞穴。

洞穴内的空气弥漫着神秘的气息,流星划过的光芒越来越亮,洞穴内的温度也开始升高。你能感受到一股无法言喻的力量,这似乎是一个新的时代的开始。

突然,洞穴内的石壁开始发出耀眼的光芒,似乎有某种能量觉醒了。你不禁一愣,然后意识到这是传说中的创世神器正在诞生。

在光芒中,一块巨大的水晶开始从石壁上升起,悬浮在空中,它就是https://github.com/dora4/dora 。这块水晶透射出五彩斑斓的光芒,你能感觉到其中蕴含的无限力量。你走近一看,石壁上镌刻着一行行整齐的铭文,原来是https://github.com/dora4/dora_samples 。你突然意识到,这石壁上的铭文似乎跟眼前这块巨大的水晶存在着某种密不可分的联系。莫非上面镌刻着这块水晶的使用方法?你思索着。

石壁开头写着这么几行文字。

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

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核心架构库https://github.com/dora4/dora 及其扩展包,比如https://github.com/dora4/dora-glide-support glide图片加载扩展包、https://github.com/dora4/dora-arouter-support arouter模块化、组件化扩展包以及https://github.com/dora4/dcache-android 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不直接建立联系。
whatis-model_view_viewmodel.png

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

step1.png

step2.png

插件项目:https://github.com/dora4/dora-studio-plugin

插件包:https://dorachat.oss-cn-hongkong.aliyuncs.com/dora-studio-plugin-1.1.jar

后记

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1699980.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

banner2.0自定义轮播布局

说明&#xff1a;最近碰到一个需求&#xff0c;让新闻列表实现轮播图的效果&#xff0c;也就是轮播新闻&#xff0c;然后样式必须按照ui设计的样式来弄&#xff0c;之前传统的banner&#xff0c;都是只轮播图片&#xff0c;没想到&#xff0c;这次居然要轮播新闻&#xff0c; 网…

夏老师小课堂(7) 免费撸Harmony0S应用开发者高级认证

点击上方 “机械电气电机杂谈 ” → 点击右上角“...” → 点选“设为星标 ★”&#xff0c;为加上机械电气电机杂谈星标&#xff0c;以后找夏老师就方便啦&#xff01;你的星标就是我更新动力&#xff0c;星标越多&#xff0c;更新越快&#xff0c;干货越多&#xff01; 关注…

C++ | Leetcode C++题解之第113题路径总和II

题目&#xff1a; 题解&#xff1a; class Solution { public:vector<vector<int>> ret;unordered_map<TreeNode*, TreeNode*> parent;void getPath(TreeNode* node) {vector<int> tmp;while (node ! nullptr) {tmp.emplace_back(node->val);node …

高效的大型语言模型适应方法:提升基础性的解决方案

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

C++系列-static成员

&#x1f308;个人主页&#xff1a;羽晨同学 &#x1f4ab;个人格言:“成为自己未来的主人~” 概念 声明为static的类成员称为类的静态成员&#xff0c;用static修饰的成员变量&#xff0c;称之为静态成员变量&#xff0c;用static修饰的成员函数&#xff0c;称之为静态成…

Django框架css文件能正常加载,但是css样式不生效

最近运行一个Django项目&#xff0c;能正常启动运行&#xff0c;css文件也能够正常加载&#xff0c;但是css样式却没有正常渲染。 解决办法&#xff1a; 1、打开注册表&#xff1a;winR 2、找到&#xff1a;计算机\HKEY_CLASSES_ROOT\.css 修改&#xff1a;Content Type 值&…

【机器学习结合AI绘画工具】——开启艺术创作的新纪元

目录 一、AI绘画工具的发展历程 二、AI绘画工具的技术原理 实例说明 三、AI绘画工具在艺术创作中的应用 实例网站 四、AI绘画工具的影响与未来展望 结论 机器学习和人工智能&#xff08;AI&#xff09;在过去的十年里取得了显著的进展。特别是在艺术创作领域&#xff0c…

linux创建离线yum源给局域网机器使用

适用场景&#xff1a;在封闭的内网环境中&#xff0c;无法使用互联网进行安装各种rpm包的时候&#xff0c;离线yum源可以解决大部分问题&#xff0c;配置号后可直接使用yum进行安装包 1.准备好镜像源ISO&#xff1a; 例如以下示例&#xff0c;具体可参考自己的系统进行下载&a…

50-Qt控件详解:Input Display

#ifndef MAINWINDOW_H #define MAINWINDOW_H#include <QMainWindow> //1.Combo Box控件 #include<QComboBox> //2.QFontComboBox控件 #include<QFontComboBox> #include<QLabel>//3.Line Edit控件 #include<QLineEdit> #include <QPushButton…

Installing Tinyproxy on CentOS 7 测试可用

Installing Tinyproxy on CentOS 7 For RHEL/CentOS 7 systems, Tinyproxy is part of EPEL (Extra Packages for Enterprise Linux). Install EPEL on CentOS 7 yum install epel-release -y yum update -y Install Tinyproxy on CentOS 7 yum install tinyproxy -y 编辑…

mysql中单表查询方法

大家好。我们知道&#xff0c;mysql有一个查询优化器的模块。当我们用sql语句查询表中记录时&#xff0c;会对这条查询语句进行语法解析&#xff0c;然后就会交给查询优化器来进行优化&#xff0c;优化后生成一个执行计划&#xff0c;这个执行计划表明了应该使用哪些索引进行查…

用这8种方法在海外媒体推广发稿平台上获得突破-华媒舍

在今天的数字时代&#xff0c;海外媒体推广发稿平台已经成为了许多机构和个人宣传和推广的有效途径。如何在这些平台上获得突破并吸引更多的关注是一个关键问题。本文将介绍8种方法&#xff0c;帮助您在海外媒体推广发稿平台上实现突破。 1. 确定目标受众 在开始使用海外媒体推…

[论文阅读笔记31]Mamba (Selective Structured State Space Model) 及其应用

最近想学一下Mamba模型&#xff0c;奈何看了很多视频还是感觉一知半解&#xff0c;因此做一篇笔记&#xff0c;顺便介绍一下Mamba结构作为CV backbone和时间序列预测领域的应用。 论文1. Mamba: Linear-Time Sequence Modeling with Selective State Spaces 0. Abstract 现有…

ModernC++(一)C++11

都在说Modern C和C不是一个东西&#xff0c;到底MordenC好在哪里&#xff0c;学了才有发言权。 why Morden C C 98的目标&#xff1a; 支持面向对象编程&#xff0c;支持泛型编程支持数据抽象 C 11的目标&#xff1a;使得C成为更好的适用于系统开发以及库开发的语言使得C语法…

宁夏银川、山东济南、中国最厉害的改名大师的老师颜廷利教授的前沿思想观点

在当代社会&#xff0c;一个响亮的声音穿越了传统的迷雾&#xff0c;它来自东方哲学的殿堂&#xff0c;由一位现代学者颜廷利教授所发出。他的话语&#xff0c;如同一股清泉&#xff0c;在混沌的世界里激荡着思考的波澜&#xff1a;"有‘智’不在年高&#xff0c;无‘智’…

第五节: 带你全面理解 vue3 中 computed, watch, watchEffect 组合式API的使用

前言: 上一章, 带大家分析了vue3核心响应式API中的三个, 即reactive,ref, readonly. 本章将会带大家分另外几个工作中比较常用的组合式API. 1. computed 计算属性 在vue2中, 我们是通过computed选项添加计算属性的, 关于计算属性的本质, 这里就不过多阐述了, 如果还有不了…

C++:函数模版简介

如果我们想要实现一个通用的交换函数&#xff0c;在C语言中&#xff0c;我们大概要定义无数个参数不同的交换函数&#xff0c;并且它们的函数名需要各不相同&#xff0c;相信这样的调用便会非常困难&#xff0c;想要调哪个函数还要记得对应的函数名。在C中&#xff0c;有了重载…

Aya 23 是 Cohere For AI 推出的一款最先进的新型多语言开放重量模型

相信一些对LLM关注较高的同学们&#xff0c;应该对这家加拿大的Cohere不会太陌生。毕竟此前&#xff0c;它就开源过 Aya 101 和 Command R 这两款大模型。 Cohere 的非营利性研究实验室 Cohere for AI 发布了 Aya 23&#xff0c;这是其多语言大型语言模型 &#xff08;llm&…

如何使用Rust构建Python原生库?注意,不是动态链接库!!!

参考文档&#xff1a;https://github.com/PyO3/pyo3 创建python虚拟环境&#xff1a; conda create --name pyo3 python3.11.7激活虚拟环境&#xff1a; conda activate pyo3安装依赖&#xff1a; pip install maturin初始化项目&#xff1a; maturin init构建项目&#x…

企业如何做好 SQL 质量管理?

研发人员写 SQL 操作数据库想必一定是一类基础且常见的工作内容。如何避免 “问题” SQL 流转到生产环境&#xff0c;保证数据质量&#xff1f;这值得被研发/DBA/运维所重视。 什么是 SQL 问题&#xff1f; 对于研发人员来说&#xff0c;在日常工作中&#xff0c;大部分都需要…