Android Weekly Issue #428

Kotlin Flow Retry Operator with Exponential Backoff Delay

这是讲协程Flow系列文章中的一篇.

对于重试的两个操作符:

  • retryWhen
  • retry

retryWhen的使用:

  1. .retryWhen { cause, attempt ->
  2. if (cause is IOException && attempt < 3) {
  3. delay(2000)
  4. return@retryWhen true
  5. } else {
  6. return@retryWhen false
  7. }
  8. }

retry:

  1. .retry(retries = 3) { cause ->
  2. if (cause is IOException) {
  3. delay(2000)
  4. return@retry true
  5. } else {
  6. return@retry false
  7. }
  8. }

可以把时间指数延长:

  1. viewModelScope.launch {
  2. var currentDelay = 1000L
  3. val delayFactor = 2
  4. doLongRunningTask()
  5. .flowOn(Dispatchers.Default)
  6. .retry(retries = 3) { cause ->
  7. if (cause is IOException) {
  8. delay(currentDelay)
  9. currentDelay = (currentDelay * delayFactor)
  10. return@retry true
  11. } else {
  12. return@retry false
  13. }
  14. }
  15. .catch {
  16. // error
  17. }
  18. .collect {
  19. // success
  20. }
  21. }

Fragments: Rebuilding the Internals

Fragment在Android 10已经废弃, 现在不在framework中了, 只在AndroidX中有.

这个Fragment 1.3.0-alpha08版本的发布, 有一些关于FragmentManager内部状态的重要更新.

解决了很多issue, 简化了fragment的生命周期, 还提供了一个FragmentManager多个back stacks的支持.

核心就是这个FragmentStateManager类.

这个FragmentStateManager负责:

  • 转换Fragment的生命周期状态.
  • 跑动画和转场.
  • 处理延迟转换.

Postponed fragments

关于状态的确定, 有一个case是一个难点: postponed fragments.

这是一个以前就有的东西, 通常跟shared element transition动画有关系.

postponed fragment有两个特点:

  • view创建了, 但是不可见.
  • lifecycle顶多到STARTED.

只有调用这个方法: startPostponedEnterTransition()之后, fragment的transition才会跑, view会变成可见, fragment会移动到RESUMED.

所以有这个bug: Postponed Fragments leave the Fragments and FragmentManager in an inconsistent state bug.

这个issue相关联的还有好几个issues.

在容器层面解决问题

用一个SpecialEffectsController(以后名字可能会改)来处理所有动画转场相关的东西.

这样FragmentManager就被解放出来, 不需要处理postponed的逻辑, 而是交给了container, 这样就避免了FragmentManager中状态不一致的问题.

新的StateManager构架

原先: 一个FragmentManager总管所有.

现在: FragmentManager和各个FragmentStateManager的实例交流.

  • The FragmentManager only has state that applies to all fragments.
  • The FragmentStateManager manages the state at the fragment level.
  • The SpecialEffectsController manages the state at the container level.

总体

这个改动新发布, 实验阶段, 总体来说是应该没有行为改变的.

如果有行为改变, 对你的程序造成了影响, 也可以暂时关闭(FragmentManager.enableNewStateManager(false)), 并且报告个issue.

A Framework For Speedy and Scalable Development Of Android UI Tests

讲了一整套的测试实践.

没有用Appium, 用的UI Automator和Espresso.

Basic Coroutine Level 1

Kotlin协程的概念.

Android Lint Framework — An Introduction

Android Lint的介绍.

创建一个Lint规则, 保证每个人都用项目自定义的ImageView, 而不是原生的ImageView.

具体做法:

  • 首先从创建一个叫做custom-lint的module. 需要依赖lint-apilint-checks:
  1. compileOnly "com.android.tools.lint:lint-api:$androidToolsVersion"
  2. compileOnly "com.android.tools.lint:lint-checks:$androidToolsVersion"

这里用了compileOnly是因为不想lint API在runtime available.

  • 之后创建自定义规则. 每个lint check的实现都叫一个detector. 需要继承Detector, 并且利用Scanners来做扫描. 报告错误需要定义Issue. 还可以创建LintFx, 作为quick fix.
  1. class ImageViewUsageDetector : LayoutDetector() {
  2. // Applicable elements
  3. override fun visitElement(context: XmlContext, element: Element) {
  4. context.report(
  5. issue = ISSUE,
  6. location = context.getElementLocation(element),
  7. message = REPORT_MESSAGE,
  8. quickfixData = computeQuickFix()
  9. )
  10. }
  11. private fun computeQuickFix(): LintFix {
  12. return LintFix.create()
  13. .replace().text(SdkConstants.IMAGE_VIEW)
  14. .with(TINTED_IMAGE_VIEW)
  15. .build()
  16. }
  17. // Issue, implementation, and other constants
  18. }
  • 然后把定义好的自定义规则注册.
  1. class Registry: IssueRegistry() {
  2. override val issues: List<Issue>
  3. get() = listOf(ImageViewUsageDetector.ISSUE)
  4. override val api: Int = CURRENT_API
  5. }
  • 创建入口, 在build.gradle文件中:

  1. // Configure jar to register our lint registry
  2. jar {
  3. manifest {
  4. attributes("Lint-Registry-v2": "com.tintedimagelint.lint.Registry")
  5. }
  6. }
  • 加上依赖和一些配置.

  1. android {
  2. // Configurations above
  3. lintOptions {
  4. lintConfig file('../analysis/lint/lint.xml')
  5. htmlOutput file("$project.buildDir/reports/lint/lint-reports.html")
  6. xmlOutput file("$project.buildDir/reports/lint/lint-reports.xml")
  7. abortOnError false
  8. }
  9. //Configurations below
  10. }
  11. dependencies {
  12. // Dependencies above
  13. // Include custom lint module as a lintCheck
  14. lintChecks project(":custom-lint")
  15. // Dependencies below
  16. }

Codelabs for new Android game technologies

关于Android Game新技术的Codelabs:

都是Unity的game.

Android Vitals - When did my app start?

系列文章之六, 我的app啥时候启动的?

看个结论吧:

Here's how we can most accurately measure the app start time when monitoring cold start:

  • Up to API 24: Use the class load time of a content provider.
  • API 24 - API 28: Use Process.getStartUptimeMillis().
  • API 28 and beyond: Use Process.getStartUptimeMillis() but filter out weird values (e.g. more than 1 min to get to Application.onCreate()) and fallback to the time ContentProvider.onCreate() is called.

Comparing Three Dependency Injection Solutions

比较三种依赖注入的解决方案.

  • 手写方式.
  • Koin.
  • Dagger Hilt.

Avoiding memory leaks when using Data Binding and View Binding

使用Data Binding和View Binding的时候, 注意内存泄漏问题.

Google建议在Fragment中使用binding时, 要在onDestroyView中置为null:

  1. private var _binding: ResultProfileBinding? = null
  2. // This property is only valid between onCreateView and
  3. // onDestroyView.
  4. private val binding get() = _binding!!
  5. override fun onCreateView(
  6. inflater: LayoutInflater,
  7. container: ViewGroup?,
  8. savedInstanceState: Bundle?
  9. ): View? {
  10. _binding = ResultProfileBinding.inflate(inflater, container, false)
  11. val view = binding.root
  12. return view
  13. }
  14. override fun onDestroyView() {
  15. super.onDestroyView()
  16. _binding = null
  17. }

有个博客中介绍的方法, 可以简化成这样:

  1. private val binding: FragmentFirstBinding by viewBinding()

Fragment还有一个参数的构造, 可以传入布局id:

  1. class FirstFragment : Fragment(R.layout.fragment_first) {
  2. private val binding: FragmentFirstBinding by viewBinding()
  3. override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
  4. super.onViewCreated(view, savedInstanceState)
  5. // Any code we used to do in onCreateView can go here instead
  6. }
  7. }

冷知识: DataBinding实现了ViewBinding.

  1. public abstract class ViewDataBinding extends BaseObservable implements ViewBinding

所以ViewBinding和DataBinding方法通用.

Anti-patterns of automated software testing

关于测试的一些anti-patterns.

推荐阅读.

Using bytecode analysis to find unused dependencies

关于这个库: https://github.com/autonomousapps/dependency-analysis-android-gradle-plugin的说明.

Code

后记

好久没在博客园发过这个系列.

其实一直还有在更, 只不过写得比较散乱随意, 所以丢在了简书:

https://www.jianshu.com/c/e51d4d597637

最近有点忙, 不太有时间写博客, 积攒了好多话题都是没有完成的.

看博客两个月没更了, 拿这篇刷一下存在感.

是想多写点真正厉害有价值的原创的.

先韬光养晦, 积累一下.

Android Weekly Notes Issue #428的更多相关文章

  1. Android Weekly Notes Issue #230

    Android Weekly Notes Issue #230 November 6th, 2016 Android Weekly Issue #230. Android Weekly笔记, 本期内容 ...

  2. Android Weekly Notes Issue #227

    Android Weekly Issue #227 October 16th, 2016 Android Weekly Issue #227. 本期内容包括: Google的Mobile Vision ...

  3. Android Weekly Notes Issue #237

    Android Weekly Issue #237 December 25th, 2016 Android Weekly Issue #237 这是本年的最后一篇issue, 感谢大家. 本期内容包括 ...

  4. Android Weekly Notes Issue #229

    Android Weekly Issue #229 October 30th, 2016 Android Weekly Issue #229 Android Weekly笔记, 本期内容包括: 性能库 ...

  5. Android Weekly Notes Issue #221

    Android Weekly Issue #221 September 4th, 2016 Android Weekly Issue #221 ARTICLES & TUTORIALS And ...

  6. Android Weekly Notes Issue #219

    Android Weekly Issue #219 August 21st, 2016 Android Weekly Issue #219 ARTICLES & TUTORIALS Andro ...

  7. Android Weekly Notes Issue #236

    Android Weekly Issue #236 December 18th, 2016 Android Weekly Issue #236 本期内容包括: Google的物联网平台Android ...

  8. Android Weekly Notes Issue #235

    Android Weekly Issue #235 December 11th, 2016 Android Weekly Issue #235 本期内容包括: 开发一个自定义View并发布为开源库的完 ...

  9. Android Weekly Notes Issue #234

    Android Weekly Issue #234 December 4th, 2016 Android Weekly Issue #234 本期内容包括: ConstraintLayout的使用; ...

随机推荐

  1. PHP quotemeta() 函数

    实例 在预定义的字符前添加反斜杠: <?php高佣联盟 www.cgewang.com$str = "Hello world. (can you hear me?)";ech ...

  2. [草稿]Skill 中的map

    https://www.cnblogs.com/yeungchie/ Skill 中的map map mapc mapcan mapcar mapcon mapinto maplist

  3. [转]HashMap 和 currentHashMap 总结

    作者:浅蓝色的麻吉 https://www.jianshu.com/p/a7767e6ff2a2 1. 什么是哈希表 在讨论哈希表之前,我们先大概了解下其他数据结构在新增,查找等基础操作执行性能 1. ...

  4. 面试被问:如果系统 CPU 突然飙升且 GC 频繁,你该如何排查?

    出自:开源中国 原文:系统运行缓慢,CPU 100%,以及Full GC次数过多问题的排查思路 处理过线上问题的同学基本上都会遇到系统突然运行缓慢,CPU 100%,以及Full GC次数过多的问题. ...

  5. 027_go语言中的通道选择器

    代码演示 package main import "fmt" import "time" func main() { c1 := make(chan strin ...

  6. wifi渗透

    前言 本文主要讲述 家庭家庭家庭中(重要的事情说三遍,企业认证服务器的wifi一般非常非常的安全破解不来)如何破解wifi密码,破解wifi密码后的内网渗透利用(简单说明),如何设置wifi路由器更安 ...

  7. MySQL数据库——查询数据

    增加数据: insert into "表名" values( '字段'',字段'); 或insert into '表名'( '字段'',字段')  values( '字段'',字段 ...

  8. 工作流选型专项,Camunda or flowable or?

    1. 名词解释 1.1. BPM Business Process Management,业务流程管理,“通过建模.自动化.管理和优化流程,打破跨部门跨系统业务过程依赖,提高业务效率和效果”. 1.2 ...

  9. 2020-04-20:对Java接口代理模式的实现原理的理解?

    静态代理Java中的静态代理要求代理类(ProxySubject)和委托类(RealSubject)都实现同一个接口(Subject).静态代理中代理类在编译期就已经确定,而动态代理则是JVM运行时动 ...

  10. Linux Centos 下安装npm 实测可用

    转载地址 https://blog.csdn.net/u012129607/article/details/60966045 1.root 登录linux 2.没有目录就自己创建一个 cd /usr/ ...