模块怎么用_Android 组件化/模块化 的理解!

aaf77f99bedaa2e74f9e294e6361b8eb.gif

作者:前行的乌龟

到现在组件化真的不是什么新鲜东西了,大公司都用的滚瓜烂熟,龙飞凤舞了,也就是现在部分中型项目和小项目在组件化的路上努力。所以同志们,组件化没玩过的,不熟悉的赶紧搞起来,说一点,你不会组件化,发布影子工程那么对你来说就是个噩梦。从本质上来讲任何技术进步都是在现实需求的逼迫下抓耳挠腮,耗尽无数头发才想出来的。哈哈,这里说个笑话罢了。所以呢组件化这个东西出来这么久了,页发展了这么久了,用的人越来越多,那肯定是对我们显示开发大有裨益的,下伙伴们不会,不熟悉抓紧啦,要不面试问你你怎么回答呢!

下面来正式说说组件化

组件化这个东西其实并不复杂,他就是种思路,本质上是一种 app 架构思路,说穿了很简单的,难在组件化改造的时候,真正写起代码会出现不少棘手的问题,当然这些坑基本前人都趟完了,这里我主要是记录下,要是你看到熟悉的部分,请不要骂我啊,毕竟都是前辈们的东西啊。

这里补充一下,组件化是一种 app 架构,他的发展也是沿着正常的技术发展脉络来的,也是为了以追求高复用,高可维护性的目的的代码封装,区别是组件化是对整个 app 的再次封装。

废话了这么多,那么什么是组件化呢,各位看官想不要着急,在详细说组件化之前,我们要搞懂2个概念,就是上面说的组件和模块。

首先组件和模块都不是官方规定的,都是这些技术发展下来大家约定俗成的概念,其实很简单,一说就明白

  • 模块:android 中的模块就是业务模块,单指业务,是按照业务对 app 进行拆分,比如说订单我们搞成一个模块,个人中心我们搞成一个模块,视频,音频这些都搞成模块,在app中的体现就是 一个个module,module 的中文意思也是模块,这不准这就是 google 对我们的暗示呢。模块化的目的是为了搭积木,随便拿几个模块module 出来就可以谁谁便便的上线一个 app,你还别说现在影子 app 的需求很旺盛,你去看看大公司的项目那个不是一堆影子工程,头条还搞出一个头条视频的马甲呢,这其实就是把视频 module 拿出来,加上一个启动页。这样的例子是比比皆是的,要不说不会组件化影子工程对你就是噩梦呢,哈哈,到时候维护那是想也别想了,代码你要搞多少份啊。

  • 组件:这个一样简单啊,说穿了就是我们平时干的事,对功能的封装,这就是组件,一个功能就是一个组件,IO,数据库,网络等等这些功能都是组件,这么说你就明白了吧。既然这样那为毛线我们还要搞出来这个一个组件的概念,当然了任何事都是有其意义的,因为组件对功能代码的封装有个很高了明确的要求:一处封装,处处使用。要我们把维护性,复用性,扩展性,性能做到极致,因为这样才能真正做到一处封装,处处使用。当然组件的范围现在也是覆盖的很广的,app 中的一切都是组件,基本上我们分为:基础功能组件,通用UI组件,基础业务组件。

以上我谈了下我自己对于模块化,组件化的理解,是目前开发中对于模块和组件的理解。在模块化和组件化的发展中概念也是有些调整变化的,大家只要看现在是什么样子就好了,深入学习的话有兴趣可以看看组件化,模块化的发展历程。

我认为 Android 模块化探索与实践 对于模块化,组件化概念的解释是最优秀的。

组件化和模块化在现在看是一回事了,如果把一个项目看成是袋中的组合的话,那么模块就是体积最大的哪些袋子,组件就是体积小的袋子,大的袋子是最直接可被外接观测和接触的袋子,大的袋子也是用小的袋子组成的,一个不太恰当的比喻吧,模块和组件就是这样的关系,是我们对业务和功能拆分,封装的理解。

好了正式开始介绍了组件化啦

组件化在工程表现上就是我们把 app 按照其业务的不同,划分为不同的 module模块,把各种功能封装成一个个 library,module 之间是严格禁止横向依赖的,要不怎么单独使用呢,我不能为了用一个 module,把相关的module 都带上吧,要是这么 module 还有依赖的module 呢,这样谈复用性就是扯淡了。

主 app 就是我们常说的壳工程依赖这些 module,library 由需求的 module 依赖,但是要考虑library 版本的问题,随着业务和功能的扩展,library 的数量也是巨大的,微信在组件化拆分时据说拆分出80多个 module,可见 library 也是少不了的。

module 和 library 多数时候我们是提供arr 和 jar 来给壳工程引用的,arr 和 jar 在编译时是不会再编译的,只会检查版本,保留一个最新的版本,既提高了 app 的编译速度,也提供一种资源冲突解决方式。

下面我放一些图来描述一下组件化,大伙仔细看看,图比文字可生动多了

d123e65c8e44ac3c54778a30d4abb98d.png
e6991258d9698e978e161808815588cd.png
modules.png
3f4e79fddd25038c648cdf843040b750.png
ad2ed5e6e413a337d89a0aa6192fc496.png
8a122de8b6a1378d4fc462d7f5e58d4a.png

项目如何组件化:

08d035544513cb67da77dd4ca8075428.png
.
8ba95258fff4cd949dc1c2d3e427eb14.png
c55cf1463ea9e634d1d3253fbd7478d6.png

组件化核心:router

我们在抽象 module 时,module 之间是没有相互依赖的,是严格解耦的,为了达到我们复用的目的。module 之间不能相互依赖,就没法调用别的 module 的代码了,那么面对业务之间的页面相互调起,相互通信这些常见的需求我们该怎么办,没错就是大伙在上面的图里面看见的东西 router。

router 是我们统一制定的模块间通讯协议,router 中我们主要是处理以下几个问题:

模块之间页面跳转
模块之间数据传递
模块初始化处理

41a1381e60689ca035c47bb033bc63f1.png
router.png

router 这东西有现成的,你也可以自己封装。使用的思路都是把 router 作为一个组件,所有的业务 module 都依赖这个 router 组件,当然壳app 也是,然后我们把需要的模块间页面跳转,数据传递,初始化都注册到 router 中,这里面就体现到我们定义的统一,通用的模块通讯协议的重要性了,router 维护多个集合保存这里关系,然后我们通过router 就可以实现模块间的通讯了。

router 的封装还是挺麻烦的,要写好了不容易,现在用的比较多的有:

  • 阿里的 ARouter

  • 最早出现的 ActivityRouter

  • spiny同学的router这是我的最爱,目前不维护了,思路很棒,并且考虑到了进程化的问题,可惜没有使用 APT 注解技术

  • 练手的 router

上面我介绍了几个 router 路由,基本上不论是自己写还是用现成的,router 基本上都是上面这几个的样子了,当然了现在好的 router 还是要使用 APT注解技术来动态去 router 注册模块方法,自己写代码去注册的话使用很使用,有些问题不好处理,比如 router 的静态实例要是被回收了,你再 new 一个出来,那么模块注册的方法怎么办,写起来太麻烦,还不如 APT 注解来的方便,扩展性也好。这里有个ToyBricks_Android项目模块化解决方案 可以解决 APT不能扫描 arr 包的问题。

最后说一下,module 间的通讯其实可以分成3种:

  • 页面调起

  • 某种事件的通知

  • 直接调用某些模块的业务方法

页面调起现在的 router 都可以很好的完成这个任务。

某些事件的通知,比如我切换城市了,通知某些页面去显示或是刷新数据,这个根据业务来说影响的范围会很广的,会影响多个业务的,因为 module 的复用性,我们在 module 中是不能确定会具体影响哪些业务module 的,那么这种场景使用 eventbus/广播比较合适了。

直接调用默写模块的业务方法,这属性业务模块间在业务上的强耦合了,这个碰到产品这么设计你也没办法,一般碰到这样的场景也是会保证相关的业务module 都是会加载的,所以呢在定义 router 灵活一些,可以做到调用指定module 的某些方法

找到另一个说法,我很喜欢,和我的理念也很接近
出自:Android 架构设计:MVC、MVP、MVVM和组件化

所谓的组件化,通俗理解就是将一个工程分成各个模块,各个模块之间相互解耦,可以独立开发并编译成一个独立的 APP 进行调试,然后又可以将各个模块组合起来整体构成一个完整的 APP。它的好处是当工程比较大的时候,便于各个开发者之间分工协作、同步开发;被分割出来的模块又可以在项目之间共享,从而达到复用的目的。组件化有诸多好处,尤其适用于比较大型的项目。

各个模块之间如何进行数据共享和数据通信?我们可以把需要共享的数据划分成一个单独的模块来放置公共数据。各个模块之间的数据通信,我们可以使用阿里的 ARouter 进行页面的跳转,使用封装之后的 RxJava 作为 EventBus 进行全局的数据通信。

router 我不想说太多,也说不好,这部分大伙看我最后的链接吧,或是看看上面4个路由也可以,不论如何实现,router 是为了给 module 模块搭建一个通讯的中间平台,目的就是这样。仔细的大家多看吧,这里我也是看别人的。

我再逼逼一下,module 和 library 我们尽量不要提供源代码的方式提供依赖,这不符合我们复用的目的,到时候你发布几个影子功能或是别的 app,那么你使用源代码依赖方式的 module 和 library 你怎么提供维护,所以尽量使用 arr 和 jar 的方式。我们可以把一些定位相近library 打包成一个 module 也是不错的。

我们一定要熟悉gradle的使用,在组件化中我们会大量的使用 gradle 提供各种资源加载的配置和环境配置

组件化最核心的目的就是代码的高可复用和高可维护和高可扩展性能,其他的优点都是属于连带性质的,我们要先把握住核心点学习,其他的都不是主要,有时间再看

组件化碰到的问题

1. 子模块单独编译测试

在做组件化开发时,我们测试 module 库都是把 module 单独达成 apk 文件,在发布module时 提供 library 供外界依赖,这都是通过配置 module 的 gradle 的编译模式实现的

首先在子模块build.gradle中定义常量,来标示模块目前是否处于开发模式

def isDebug = true
在子模块的build.gradle中进行模式配置。debug模式下编译成独立app,release模式下编译成library。

1if (isDebug.toBoolean()) {
2    apply plugin: 'com.android.application'
3} else {
4    apply plugin: 'com.android.library'
5}

两种模式下模块AndroidManifest.xml文件是有差别的。作为独立运行的app,有自己的Application,要加Launcher的入口intent,作为library不需要。这个问题很好解决,写两个不同的AndroidManifest.xml即可,并在gradle中进行配置。

a53d48f582a37096017aafe80039bf09.png

在 gradle 脚本中配置

 1android {
2    sourceSets {
3        main {
4            if(isDebug.toBoolean()) {
5                manifest.srcFile 'src/debug/AndroidManifest.xml'
6            } else {
7                manifest.srcFile 'src/release/AndroidManifest.xml'
8            }
9        }
10    }
11}

2. sdk和第三方库的版本一致性

不同module依赖sdk版本不一致,会因兼容性问题导致编译问题。
不同module引用了同一个第三方库的不同版本,并且这个库没有做到向前兼容,就有可能出现方法找不到、参数不对应等问题。
所以有必要统一整个project的依赖版本。

在最外层build.gradle中定义的常量能被整个project的build.gradle文件引用,统一的版本定义可以放在这里。

 1ext {
2    android_compileSdkVersion = 25
3    android_buildToolsVersion = '25.0.2'
4    android_minSdkVersion = 21
5    android_targetSdkVersion = 25
6
7    lib_appcompat = 'com.android.support:appcompat-v7:25.1.1'
8    lib_picasso = 'com.squareup.picasso:picasso:2.5.2'
9    lib_gson = 'com.google.code.gson:gson:2.6.1'
10}

我没试过 arr资源的 module 是否还可以使用这种方式

3. 资源id冲突

android 中 module的资源文件最后都是会合并到主项目中的,资源文件的 id 最终和 moudle 是的 id 是不一样的,所以这就会出现资源重名的问题,解决这个问题,我们的做法就是module 资源加一个统一的前缀

 1andorid{
2    ...
3
4    buildTypes{
5        ...
6    }
7
8    resourcePrefix "moudle_prefix"
9
10}

但是注意 res 文件夹下的文件可以用 gradle 脚本加前缀,但是图片资源不行,图片资源我们还是需要在命名时自己添加前缀

4. application初始化的问题

子模块作为application时,有一些初始化的工作需要在Application.onCreate时进行。而作为library时,调不到这个onCreate。所以自己写一个静态方法,供主工程的Application调用。

 1public class ApplicationA extends Application {
2
3@Override public void onCreate() {
4  super.onCreate();
5  //给底层library设置context
6  AppContext.init(getApplicationContext());
7}
8  /** 9   * 作为library时需要初始化的内容10   */
11  public static void onCreateAsLibrary() {
12    //给FunctionBus传入接口的实例
13    FunctionBus.setFunction(new FunctionA() {
14      @Override public String getData(String key) {
15        return "xixi";
16      }
17    });
18  }
19}

主工程的Application onCreate时记得初始化子模块。

1public class MainApplication extends Application {
2
3  @Override public void onCreate() {
4    super.onCreate();
5    AppContext.init(getApplicationContext());
6    ApplicationA.onCreateAsLibrary();
7    ApplicationB.onCreateAsLibrary();
8  }
9}

除了提供方法在壳工程里面调用,还可以结合使用了 APT 技术的 router 来做,使用注解,就不用我们自己去调用了,彻底解耦

5. library依赖问题

先说一个问题,在组件化工程模型图中,多媒体组件和Common组件都依赖了日志组件,而A业务组件有同时依赖了多媒体组件和Common组件,这时候就会有人问,你这样搞岂不是日志组件要被重复依赖了,而且Common组件也被每一个业务组件依赖了,这样不出问题吗?

其实大家完全没有必要担心这个问题,如果真有重复依赖的问题,在你编译打包的时候就会报错,如果你还是不相信的话可以反编译下最后打包出来的APP,看看里面的代码你就知道了。组件只是我们在代码开发阶段中为了方便叫的一个术语,在组件被打包进APP的时候是没有这个概念的,这些组件最后都会被打包成arr包,然后被app壳工程所依赖,在构建APP的过程中Gradle会自动将重复的arr包排除,APP中也就不会存在相同的代码了;

但是虽然组件是不会重复了,但是我们还是要考虑另一个情况,我们在build.gradle中compile的第三方库,例如AndroidSupport库经常会被一些开源的控件所依赖,而我们自己一定也会compile AndroidSupport库 ,这就会造成第三方包和我们自己的包存在重复加载,解决办法就是找出那个多出来的库,并将多出来的库给排除掉,而且Gradle也是支持这样做的,分别有两种方式:根据组件名排除或者根据包名排除,下面以排除support-v4库为例:

1dependencies {
2    compile fileTree(dir: 'libs', include: ['*.jar'])3    compile("com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion") {
4        exlude module: 'support-v4'//根据组件名排除
5        exlude group: 'android.support.v4'//根据包名排除
6    }
7}

library重复依赖的问题算是都解决了,但是我们在开发项目的时候会依赖很多开源库,而这些库每个组件都需要用到,要是每个组件都去依赖一遍也是很麻烦的,尤其是给这些库升级的时候,为了方便我们统一管理第三方库,我们将给给整个工程提供统一的依赖第三方库的入口,前面介绍的Common库的作用之一就是统一依赖开源库,因为其他业务组件都依赖了Common库,所以这些业务组件也就间接依赖了Common所依赖的开源库。

 1dependencies {
2    compile fileTree(dir: 'libs', include: ['*.jar']) 3    //Android Support 4    compile "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion" 5    compile "com.android.support:design:$rootProject.supportLibraryVersion" 6    compile "com.android.support:percent:$rootProject.supportLibraryVersion" 7    //网络请求相关 8    compile "com.squareup.retrofit2:retrofit:$rootProject.retrofitVersion" 9    compile "com.squareup.retrofit2:retrofit-mock:$rootProject.retrofitVersion"10    compile "com.github.franmontiel:PersistentCookieJar:$rootProject.cookieVersion"11    //稳定的12    compile "com.github.bumptech.glide:glide:$rootProject.glideVersion"13    compile "com.orhanobut:logger:$rootProject.loggerVersion"14    compile "org.greenrobot:eventbus:$rootProject.eventbusVersion"15    compile "com.google.code.gson:gson:$rootProject.gsonVersion"16    compile "com.github.chrisbanes:PhotoView:$rootProject.photoViewVersion"1718    compile "com.jude:easyrecyclerview:$rootProject.easyRecyclerVersion"19    compile "com.github.GrenderG:Toasty:$rootProject.toastyVersion"2021    //router22    compile "com.github.mzule.activityrouter:activityrouter:$rootProject.routerVersion"23}24

6. module不同业务环境使用不同代码

我们做项目至少会有测试和线上2套环境吧,组件化让我们开始重视 gradle,通过 gradle 配置我们可以减少很多代码的书写的,切换环境我们也是可以用 gradle 实现的,在不通过的环境下注册不同的代码文件,看下面这张图

bca2480981366e22ce4d002db92dff2d.png

我们有 debug 和 release2个环境,里面放的是不同环境执行的代码,main 里面是跟环境切换无关的代码部分,我我们这样设置 gradle 就可以了

 1android {
2    // ...
3    sourceSets {
4        debug {
5            java.srcDirs = ['src/main/java', 'src/debug/java']
6        }
7        release {
8            java.srcDirs = ['src/main/java', 'src/release/java']
9        }
10    }
11}

此外在发布该 library 时,需要指定一些设置,如下:

1android {
2    // ...
3    defaultConfig {
4        // ...
5        defaultPublishConfig 'release'
6        publishNonDefault true
7    }
8}

说明:

  • defaultPublishConfig 'release',默认 library 只会生产 release 下的版本,此版本将会被所有项目使用,通过defaultPublishConfig可以控制默认生产哪个版本的库。

  • publishNonDefault true,默认情况下不能生产所有版本的 library,通过设置publishNonDefault为true,可以同时生产所有版本的 library。
    业务组件 module 依赖不同的基础组件生产的 library,如下:

1dependencies {
2    // ...
3    debugCompile project(path: ':baselibrary', configuration: "debug")4    releaseCompile project(path: ':baselibrary', configuration: "release")5}6

在使用通过这样的配置脚本解决了多个 APK 包依赖同一组件生产的不同的 library,最终得到我们需要的开发/测试/生产 APK 包。

合并多个 module 到一个文件夹

studio 中的 module 我们在引用时都是用,项目名 + :冒号来表示的

1implementation project(':basecomponents')2

注意这只是表示我们要引用这个名字的 module 了,而这个 module 的地址这里我们不管

那么就可以理解为 module 的地址可以随我们任意配置,那么在哪里配置 module 的地址呢,答案就是在 setting.gradle 文件里,我们给 ':basecomponents' 这个 module 指定他的地址就行

比如我们想新建一个名字为 components 的文件夹存放我们的组件 module ,组件我们给2个 ( basecomponents,aaa ),然后我们在 setting.gradle 里指定每个项目的文件路径

1include ':app', ':basecomponents', ':aaa'
2
3project(':basecomponents').projectDir = new File( 'components/basecomponents' )
4project(':aaa').projectDir = new File( 'components/aaa' )
16b847c2af2c609955e64487b80ad85b.png

一个好的组件化文档是必须的

组件化是 android 开发步入新时代的未来,是代码膨胀,支持快速开发的必然,一个好的组件化文档在现今来看也是必须的了

下面贴个图

089256017f6835b0cc84ec7dae3aef48.png
474fb5d9248418157ce338ceba759e51.png

组件化的坑

组件化是好,但是坑也是不少,不好填,尤其是 databinding,dagger,bufferkinft,这是源于 studio 编译的问题。

studio 中 module 虽然是在代码上独立于壳工程的,但是在编译时最后还是要合并到壳工程中的,要不怎么达成一个 APK 文件,要是多个 APK 文件把不成了插件化了嘛,插件化坑更多啊。合并 module 到壳工程就会产生一个根本问题,module 的 R 文件数值改变了。module 的 R文件数据不是固定的,只有壳工程的 R 文件才是常量值,时不变的,module 的 R 文件数值在把 modul 的资源合并到壳工程后才会确定下来,那么这就对依靠编译时注解的技术造成了难题,你指定的 R 路径最后找不到,并且据说这里面还涉及注解的 final ,不了解,看到有人这么说,所以大家在开发组件化时对于带注解技术的框架要多注意,有坑要多看才能爬过去

组件化文章:
Android 模块化探索与实践 安居客的时间案例,对概念的解释非常到位,适合初学者和概念混乱的同学看,特别是有提供详细的 demo 哦

关于Android模块化我有一些话不知当讲不 这是我目前看到的最贴近实际的好文了,绝对值得一看的

Android组件化方案

https://blog.csdn.net/guiying712/article/details/55213884

这篇文章讲的最好,还设计大量 gradle 配置的思考

android开发:由模块化到组件化

https://blog.csdn.net/dd864140130/article/details/53645290)

优秀的组件化方案:

Android彻底组件化方案实践

https://www.jianshu.com/p/1b1d77f58e84

Android彻底组件化demo发布

https://www.jianshu.com/p/59822a7b2fad

---END---

推荐阅读:
2020年10月编程语言排行榜:C语言登顶,Java下滑~
“终于懂了” 系列:Android屏幕刷新机制—VSync、Choreographer 全面理解!
25岁程序员 VS 35岁程序员,你中了几条?!
有同学这么设置Intellij IDEA,据说效率还不错~
细数 2020 年官方对 Android 的那些重大更新!
Android Debug 调试原理!
再见!onActivityResult!你好,Activity Results API!
面试官邪魅一笑: 你说说 Java8 的 ConcurrentHashMap ?

597f50ffa80987409ffcd0197836d3d8.png

更文不易,点个“在看”支持一下?

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

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

相关文章

和get redis_SpringBoot整合Redis,你get了吗?

Our-task介绍本篇博客是我github上our-task:一个完整的清单管理系统的配套教程文档,这是SpringBootVue开发的前后端分离清单管理工具,仿滴答清单。目前已部署在阿里云ECS上,可进行在线预览,随意使用(附详细…

树莓派 触摸屏_如何用树莓派搭建一个颗粒物(PM2.5)传感器

用树莓派、一个廉价的传感器和一个便宜的屏幕监测空气质量。-- Stephan Tetzel(作者)大约一年前,我写了一篇关于如何使用树莓派和廉价传感器测量 空气质量 的文章。我们这几年已在学校里和私下使用了这个项目。然而它有一个缺点:由于它基于无线/有线网&a…

matlab肌电信号平滑滤波_MATLAB图像处理:43:用高斯平滑滤波器处理图像

本示例说明了如何使用imgaussfilt来对图像应用不同的高斯平滑滤波器。高斯平滑滤波器通常用于降低噪声。将图像读入工作区。I imread(cameraman.tif);使用各向同性的高斯平滑核增加标准偏差来过滤图像。高斯滤波器通常是各向同性的,也就是说,它们在两个…

Github 简明教程 - 添加远程库

现在的情景是,你已经在本地创建了一个Git仓库后,又想在GitHub创建一个Git仓库,并且让这两个仓库进行远程同步,这样,GitHub上的仓库既可以作为备份,又可以让其他人通过该仓库来协作,真是一举多得…

分享AI有道干货 | 126 篇 AI 原创文章精选(ML、DL、资源、教程)

一年多来,公众号【AI有道】已经发布了 140 的原创文章了。内容涉及林轩田机器学习课程笔记、吴恩达 deeplearning.ai 课程笔记、机器学习、深度学习、笔试面试题、资源教程等等。值得一提的是每篇文章都是我用心整理的,编者一贯坚持使用通俗形象的语言给…

c语言qt生成dll与加载dll,Qt制作界面的DLL以及调用

1、将界面做成dll修改pro文件DEFINES WIDGETDLL_LIBRARYTEMPLATE lib修改头文件#if defined(WIDGETDLL_LIBRARY)# define WIDGETDLLSHARED_EXPORT Q_DECL_EXPORT#else# define WIDGETDLLSHARED_EXPORT Q_DECL_IMPORT#endifclass WIDGETDLLSHARED_EXPORT WidgetDll:public QWi…

20162329 张旭升 2017 - 2018 《程序设计与数据结构》第五周总结

20162329 2017-2018-1 《程序设计与数据结构》第五周学习总结 教材学习内容总结 1.学习目标 了解集合的概念了解并使用抽象数据类型初步了解使用Java泛型学习栈这种数据结构用数组、链表实现栈2.学习内容 集合的概念: 集合是手机并组织其他对象的对象,他…

centos 安装trace_前期的准备工作-MacOS Mojave 10.14.3 下安装CentOS 7及Bochs 002

MacOS Mojave 10.14.3 下使用虚拟机安装CentOS 7 以及 Bochs 2.6.9CentOS 7.6.1810 系统下 安装Bochs 2.6.91 下载CentOS 7.6.1810网址为https://www.centos.org/遇到的问题安装后无法使用使用网络,最简单的解决方法就是增加一个新的网络适配器,使用Nat共…

事件处理程序

转载于:https://www.cnblogs.com/ypx666/p/10869448.html

脉冲时间宽度c语言,基于AT89C52脉冲宽度测量仪的设计与实现

赵翠玉摘要:本文基于AT89C52的脉冲宽度测量仪的设计。该仪器测量结果采用了软件数字滤波,消除了测量中抖动问题,测量精度高、稳定性好,具有一定的实用性。关键词:AT89C52;测量仪;脉冲宽度中图分类号:TM935.…

[转载] mysql 索引中的USING BTREE 的意义

索引是在存储引擎中实现的,因此每种存储引擎的索引都不一定完全相同,并且每种存储引擎也不一定支持所有索引类型。 根据存储引擎定义每个表的最大索引数和最大索引长度。所有存储引擎支持每个表至少16个索引,总索引长度至少为256字节。 大多数…

【BZOJ1857】【SCOI2010】传送带 [三分]

传送带 Time Limit: 1 Sec Memory Limit: 64 MB[Submit][Status][Discuss]Description 在一个2维平面上有两条传送带,每一条传送带可以看成是一条线段。两条传送带分别为线段AB和线段CD。lxhgww在AB上的移动速度为P,在CD上的移动速度为Q,在平…

google android广告异步加载,谷歌广告异步代码和同步代码的解决方法

通常大部分人初次接触谷歌google adsense广告联盟都会有疑问,在新建单元界面我们可以看到获取代码类型选项。下面是学习啦小编为大家整理的关于谷歌广告异步代码和同步代码的解决方法,一起来看看吧!谷歌广告异步代码和同步代码的解决方法选择同步还是异步…

使用Docker 安装Elasticsearch、Elasticsearch-head、IK分词器 和使用

使用Docker 安装Elasticsearch、Elasticsearch-head、IK分词器 和使用 原文:使用Docker 安装Elasticsearch、Elasticsearch-head、IK分词器 和使用Elasticsearch的安装 一、elasticsearch的安装 1.镜像拉取 docker pull elasticsearch:tag2.启动 docker run -it -e "disc…

Spring 的持久化实例(JDBC, JdbcTemplate、HibernateDaoSupport、JdbcDaoSupport、SqlSessionDaoSupport等)...

2019独角兽企业重金招聘Python工程师标准>>> 一、表(这里用mysql,数据库名为yiibai) CREATE TABLE customer (CUST_ID int(10) UNSIGNED NOT NULL,NAME varchar(100) NOT NULL,AGE int(10) UNSIGNED NOT NULL ) ENGINEInnoDB DEFA…

麦克劳林展开式_数学家麦克劳林与牛顿的故事

数学家麦克劳林麦克劳林(Colin Maclaurin1698年2月-1746年6月), 苏格兰数学家,麦克劳林是18世纪英国最具有影响的数学家之一。01麦克劳林是一位牧师的儿子,半岁丧父,9岁丧母。由其叔父抚养成人。叔父也是一位牧师。麦克劳林是一个“神童”&am…

微信小程序把玩(三十三)Record API

微信小程序把玩(三十三)Record API 原文:微信小程序把玩(三十三)Record API其实这个API也挺奇葩的,录音结束后success不走,complete不走,fail也不走, 不知道是不是因为电脑测试的原因…

如何获取元素在父级div里的位置_关于元素的浮动你了解多少

首先,在介绍什么是浮动之前我们先介绍一下html中元素的普通流布局方式。在普通流中,元素是按照它在 HTML 中的出现的先后顺序自上而下依次排列布局的,在排列过程中所有的行内元素水平排列,直到当行被占满然后换行,块级…

Java电商项目-5.内容管理cms系统

目录 实现加载内容分类树功能实现内容分类动态添加删除内容分类节点实现内容分类节点的分页显示实现广告内容的添加实现广告内容删除实现广告内容编辑到Github获取源码请点击此处实现加载内容分类树功能 注: 往后将不在说编写远程服务方法和编写web模块等重复语句, 直接用"…

【JS新手教程】LODOP打印复选框选中的任务或页数

之前的博文:【JS新手教程】LODOP打印复选框选中的内容关于任务:Lodop打印语句最基本结构介绍(什么是一个任务)关于本文用到的JS的eval方法:JS-JAVASCRIPT的eval()方法该文用的是不同checkbox,对应不同的val…