Android App 组件化构架

目前架构一共分为四层, 从低到高依次是基础层,项目封装(如果不需要可能跳过这层),业务层和宿主层。 宿主层 宿主层位于最上层, 主要作用是作为一个 App 壳, 将需要的模块组装成一个完整的 App, 这一层可以管理整个 App 的生命周期(比如 Application 的初始化和各种组件以及三方库的初始化) 业务层 业务层位于中层, 里面主要是根据业务需求和应用场景拆分过后的业务模块, 每个模块之间互不依赖, 但又可以相互交互, 比如一个商城 App 由 搜索, 订单, 购物车, 支付 等业务模块组成 Tips: 每个业务模块都可以拥有自己独有的 SDK 依赖和自己独有的 UI 资源 (如果是其他业务模块都可以通用的 SDK 依赖 和 UI 资源 就可以将它们抽离到基础SDK中) 业务模块的拆分 写业务之前先不要急着动手敲码, 应该先根据初期的产品需求到后期的运营规划结合起来清晰的梳理一下业务在未来可能会发生的发展, 确定业务之间的边界, 以及可能会发生的变化, 最后再确定下来真正需要拆分出来的业务模块再进行拆分 项目封装 项目封装主要是为了解决:同一个公司如果有多个项目,在处理 登录、用户数据、接口定义…上一般来说是相同的,所以在此对相同的模块进行一次封装。 基础层 基础层位于最底层, 里面又包括公共服务模块、 基础 SDK 模块, 核心基础业务模块 和 公共服务模块 主要为业务层的每个模块服务, 基础 SDK 模块 含有各种功能强大的团队自行封装的 SDK 以及第三方 SDK, 为整个平台的基础设施建设提供动力。个人认为,基础模块是一个可以脱离上层独立应用于各种app开发架构的模块,所以,基础模块应该是不包含各种业务逻辑处理,对网络、图片加载、SDK的封装不应该包含特定业务的处理 核心基础业务 核心基础业务 为 业务层 的每个业务模块提供一些与业务有关的基础服务, 比如在项目中以用户角色分为 2 个端口, 用户可以扮演多个角色, 但是在线上只能同时操作一个端口的业务, 这时每个端口都必须提供一个角色切换的功能, 以供用户随时在多个角色中切换, 这时在项目中就需要提供一个用于用户自由切换角色的管理类作为 核心基础业务 被这 2 个端口所依赖(类似 拉勾, Boss 直聘等 App 可以在招聘者和应聘者之间切换)...

十二月 4, 2018 · 1 分钟 · LengYue

MediaCodec实现视频音视频分离、合并、编辑、压缩

介绍 android上视频操作,主要有OpenGL、FFmpeg、以及4.1之后的MediaCodec,MediaCodec是Android上一个用来直接访问设备的媒体编解码器的接口,因为有硬件加速的效果,所以使用起来无论是效率,还是耗时,都会比FFmpeg好很多,今天了着重谈谈MediaCodec的使用。 与MediaCodec相关,经常配合一起使用的媒体处理类主要有: MediaExtractor用于音视频分路,和MediaMuxer正好是反过程。MediaFormat用于描述多媒体数据的格式。MediaRecorder用于录像+压缩编码,生成编码好的文件如mp4, 3gpp,视频主要是用于录制Camera preview。MediaPlayer用于播放压缩编码后的音视频文件。AudioRecord用于录制PCM数据。AudioTrack用于播放PCM数据 音视频分离 视频的分离和合成主要是用MediaExtractor和MediaMuxer这两个类,来处理视频中的视频信道和音频信道的拆分和组合。 逻辑大概如下: 1.初始化对象,设置源文件 var extractor = MediaExtractor() extractor.setDataSource(videoPath.absolutePath) 2.获取要追踪的TrackIndex 信道track index //获得信道数 val trackCount = extractor.trackCount var videoTrack = -1 var audioTrack = -1 for (i in 0 until trackCount) { val trackFormat = extractor.getTrackFormat(i) val format = trackFormat.getString(MediaFormat.KEY_MIME) //视频信道 if (format.startsWith("video/")) { videoTrack = i } if (format.startsWith("audio/")) { audioTrack = i } } 打开MediaFormat可以看到所有支持的mime...

十一月 5, 2018 · 3 分钟 · LengYue

Glide4加载图片RoundedCorners跟CenterCrop冲突问题解决

在glide4.0上面 centerCrop和圆角图片有冲突只能显示一个 类似这个: Glide.with(TPApplication.getAppContext()) .load(url) .centerCrop() .transform(glideRoundTransform) .placeholder(R.drawable.nearby_online_me_photo) .diskCacheStrategy(DiskCacheStrategy.ALL) .dontAnimate() .into(this); 分析 点开centerCrop()这个代。 /** * Applies {@link CenterCrop} to all default types and * throws an exception if asked to transform an unknown type. * * <p>this will override previous calls to {@link #dontTransform()} ()}. * * @see #transform(Class, Transformation) * @see #optionalCenterCrop() */ public RequestOptions centerCrop() { return transform(DownsampleStrategy.CENTER_OUTSIDE, new CenterCrop()); } 可以看到CenterCrop也是调用的 transform的方法,在点开 new Centercrop()这个方法看看里面的实现...

十月 25, 2018 · 1 分钟 · LengYue

优雅的给显示超长字符串的TextView加上省略号

TextView应该是Android开发中使用频次非常高的一个基础控件。对于长文本,TextView默认的处理方案是换行显示,对于只需要单行显示的TextView加上android:singleLine="true"即可让TextView单行显示,同时如果文本超过一行自动加上省略号,但是如果UI是类似这种呢?再只使用一个控件的情况下,实现的这样的显示目前能想到的有一下几种。 计算文字行数 第一种方法思路很简单,要实现这种效果只需要在还没有进行settext方法之前就先判断一下文本是否超长,如果超过一行的长度就把第一行取出来,进行手动拼接后(第一行文本+…等X人)设置到TextView上 计算文本是否有多行 TextView自身就限制行数的API所以,判断文本有几行,这代码TextView肯定已经有了,我们打开TextView的源代码,果不其然 ··· final StaticLayout.Builder layoutBuilder = StaticLayout.Builder.obtain( text, 0, text.length(), mTempTextPaint, Math.round(availableSpace.right)); layoutBuilder.setAlignment(getLayoutAlignment()) .setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier()) .setIncludePad(getIncludeFontPadding()) .setBreakStrategy(getBreakStrategy()) .setHyphenationFrequency(getHyphenationFrequency()) .setJustificationMode(getJustificationMode()) .setMaxLines(mMaxMode == LINES ? mMaximum : Integer.MAX_VALUE) .setTextDirection(getTextDirectionHeuristic()); final StaticLayout layout = layoutBuilder.build(); // Lines overflow. if (maxLines != -1 && layout.getLineCount() > maxLines) { return false; } ··· layout....

九月 22, 2018 · 1 分钟 · LengYue

Android全新支持库androidx

如果使用最新版Android Studio 创建基于API28的项目,就会发现,原来的android.support.*全部变成了androidx.*??这是什么鬼?我们来看看Google的介绍 我们正在推出一种新的软件包结构,以便更清楚哪些软件包与Android操作系统捆绑在一起,并与您的应用程序的APK一起打包。展望未来,android.*软件包层次结构将保留给随操作系统提供的Android软件包; 其他包将在新的androidx.*包层次结构中发布。 正在重构现有包以使用新层次结构。历史文物 - 那些版本为27及更早版本,并打包为android.support.*- 将继续在Google Maven上提供; 但是,所有新开发都将发生在androidx.*从1.0.0开始版本化的新打包工件中。 有关所有旧类和构建工件的完整映射到新的,请参阅AndroidX重构页面。有关AndroidX重构的更多信息, 请参阅博客文章。 版本控制更改 新工件将遵循语义版本控制,并将独立更新,而不是一次更新。重组后,可以独立更新项目中的AndroidX库。这避免了将项目中的许多支持库模块从例如一次更新26.1.0到27.0.0所有支持库模块的问题。 新项目 如果使用androidx打包的依赖项创建新项目(而不是使用Android Studio工具重构现有项目),则新项目需要针对API级别28,并且您需要将以下行添加到您的gradle.properties文件中: android.useAndroidX=true android.enableJetifier=true 简而言之,support包会继续维护,但是所有新特性都会放到androidx中,如果想使用androidx,需要API为28(IDE应该也需要最新版本),同时gradle.properties中添加 android.useAndroidX=true android.enableJetifier=true,反之不想使用设置为false即可,需要注意的是即使依赖中不添加 implementation androidx.*相关的支持库,如果gradle.properties中设置为true 仍然使用androidx相关支持库,android.support相关引用会提示not found

九月 13, 2018 · 1 分钟 · LengYue

新版本Gradle修改打包的路径和文件名

这里分为Gradle3.0之前和之后两种方法。 3.0之前 在release 下添加下面代码 applicationVariants.all { variant -> variant.outputs.each { output -> if (outputFile != null && outputFile.name.endsWith('.apk')) { def apkFile = new File( output.outputFile.getParent(), "${defaultConfig.versionName}_${variant.productFlavors[0].name}.apk") output.outputFile = apkFile } } } 3.0之后 3.0之后不允许修改 output.outputFile 会提示报错。 applicationVariants.all { variant -> variant.outputs.all { output -> def outputFile = output.outputFile if (outputFile != null && outputFile.name.endsWith('.apk')) { def fileName = "${defaultConfig....

九月 8, 2018 · 1 分钟 · LengYue

Flutter 下一些常用的插件

库 功能 dio 网络框架 shared_preferences 本地数据缓存 fluttertoast toast flutter_redux redux device_info 设备信息 connectivity 网络链接 flutter_markdown markdown解析 json_annotation json模板 json_serializable json模板 url_launcher 启动外部浏览器 iconfont 字库图标 share 系统分享 flutter_spinkit 加载框样式 get_version 版本信息 flutter_webview_plugin 全屏的webview sqflite 数据库 flutter_statusbar 状态栏 flutter_svg svg photo_view 图片预览 flutter_slidable 侧滑

九月 4, 2018 · 1 分钟 · LengYue

Android 5.0一下分包最新解决办法

建议参照最新官方提供的分包方式 (科学上网)进行分包,具体配置方式在 multiDexKeepProguard 属性下 第一步、新建文件 app Module 下,新建一个名为multidex-config.pro的文件 文件内具体内容实例: -keep class me.passin.pmvp.app.GlobalConfiguration 即想把哪个类分在主Dex 则 -keep class 类名。 如果您想要指定包中的所有类,文件将如下所示: -keep class com.example.** { *; } 第二步、App模块的build.gradle添加配置参数 android { buildTypes{ release{ multiDexKeepProguard file('multidex-config.pro') } } }

八月 29, 2018 · 1 分钟 · LengYue