模块怎么用_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,一经查实,立即删除!

相关文章

操作系统基础

操作系统基础一个完整的操作系统包括 ( kernel application)内核 应用程序而我们要学习操作系统:Linux操作系统我们平时所用的WINDOWS和MS-DOS都是微软出的,而Linux不是微软出的,Linux的最大好处是非商业软件&#x…

leetcode1247. 交换字符使得字符串相同(贪心)

有两个长度相同的字符串 s1 和 s2,且它们其中 只含有 字符 “x” 和 “y”,你需要通过「交换字符」的方式使这两个字符串相同。 每次「交换字符」的时候,你都可以在两个字符串中各选一个字符进行交换。 交换只能发生在两个不同的字符串之间…

interop_如何在Blazor中实现JavaScript Interop

interop介绍 (Introduction) In this article, we will learn about JavaScript Interop in Blazor. We will understand what JavaScript Interop is and how we can implement it in Blazor with the help of a sample application.在本文中,我们将学习Blazor中Ja…

Centos 7和 Centos 6开放查看端口 防火墙关闭打开

Centos 7 firewall 命令: 查看已经开放的端口: firewall-cmd --list-ports 开启端口 firewall-cmd --zonepublic --add-port80/tcp --permanent 命令含义: –zone #作用域 –add-port80/tcp #添加端口,格式为:端口/通讯…

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

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

linux课程设计qq,仿QQ聊天系统课程设计.doc

目录绪论1一.需求分析11.1软件功能需求分析21.2 安全需求分析2二.总体设计32.1 软件结构图32.2 功能描述32.2.1注册功能概要42.2.2登录功能概要42.2.3聊天功能概要52.3 安全设计6三.数据库设计63.1概念结构设计63.2逻辑结构设计73.3物理结构设…

ocp linux 基础要点

基本命令: 创建/修改/删除用户 useradd/usermod/userdel 创建/修改/删除用户组 groupadd/groupmod/groupdel 修改所属用户/所属用户组 chown/chgrp 修改权限 chmod 创建文件夹 mkdir 创建文件 touch 切换目录 …

leetcode1386. 安排电影院座位(贪心)

如上图所示,电影院的观影厅中有 n 行座位,行编号从 1 到 n ,且每一行内总共有 10 个座位,列编号从 1 到 10 。 给你数组 reservedSeats ,包含所有已经被预约了的座位。比如说,researvedSeats[i][3,8] &…

首席技术执行官_如何在几分钟内找到任何首席执行官的电子邮件地址

首席技术执行官by Theo Strauss由西奥斯特劳斯(Theo Strauss) 如何在几分钟内找到任何首席执行官的电子邮件地址 (How to find any CEO’s email address in minutes) 银河电子邮件指南:第一部分 (The Emailer’s Guide To The Galaxy: Part I) I’m 17, so my net…

Linux 查看磁盘或文件夹及文件大小

当磁盘大小超过标准时会有报警提示,这时如果掌握df和du命令是非常明智的选择。 df可以查看一级文件夹大小、使用比例、档案系统及其挂入点,但对文件却无能为力。 du可以查看文件及文件夹的大小。 两者配合使用,非常有效。比如用df查看哪个…

Python列表基础

列表:创建列表:list[] 注意:列表里面类型可以是不同的类型 取值:list[2]   替换:注意不要越界(下表超出了可表示范围) 操作: 合并列表:   list3list2list1 列表的重复:   (list8*3)   判断元素是否…

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

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

shell 25个常用命令

1.列出所有目录使用量,并按大小排序。 ls|xargs du -h|sort -rn #不递归下级目录使用du -sh2.查看文件排除以#开关和空白行,适合查看配置文件。 egrep -v "^#|^$" filenamesed /#.*$/d; /^ *$/d3.删除空格和空行。 sed /^$/d filename #删除空…

tensorflow入门_TensorFlow法律和统计入门

tensorflow入门by Daniel Deutsch由Daniel Deutsch TensorFlow法律和统计入门 (Get started with TensorFlow on law and statistics) What this is about 这是关于什么的 What we will use 我们将使用什么 Get started 开始吧 Shell commands for installing everything you …

centos7 nginx+php5.6+mysql安装与配置

安装与配置 php 56的安装 php的配置写在 php.ini,可在phpinfo()中查看 //查找已安装 yum list installed | grep php // php卸载 yum -y remove php56* yum remove httpd* php* 可用的资源:centos 安装php56nginx nginx php-fpm nginx安装 sudo rpm -Uv…

leetcode337. 打家劫舍 III(dfs)

在上次打劫完一条街道之后和一圈房屋后,小偷又发现了一个新的可行窃的地区。这个地区只有一个入口,我们称之为“根”。 除了“根”之外,每栋房子有且只有一个“父“房子与之相连。一番侦察之后,聪明的小偷意识到“这个地方的所有房…

c语言面试题东软,2012东软笔试题

1、下列变量定义错误的是Dint a;double b4.5;boolean btrue;float f9.8; (9.8f)2、65%32的值是 D 3%53219103、对于一个三位的正整数 n,取出它的十位数字k(k为整型)的表达式是k n / 10 % 10k ( n - n / 100 * 100 )k n % 10k n / 104、下列语句序列执…

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

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

Github 简明教程 - 添加远程库

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

githooks_使用Githooks改善团队的开发工作流程

githooksby Daniel Deutsch由Daniel Deutsch 使用Githooks改善团队的开发工作流程 (Improve your team’s development workflow with Githooks) Every product that is developed by more than one programmer needs to have some guidelines to harmonize the workflow.由多…