Android Weekly Issue #428

Kotlin Flow Retry Operator with Exponential Backoff Delay

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

对于重试的两个操作符:

  • retryWhen
  • retry

retryWhen的使用:

.retryWhen { cause, attempt ->
if (cause is IOException && attempt < 3) {
delay(2000)
return@retryWhen true
} else {
return@retryWhen false
}
}

retry:

.retry(retries = 3) { cause ->
if (cause is IOException) {
delay(2000)
return@retry true
} else {
return@retry false
}
}

可以把时间指数延长:

viewModelScope.launch {
var currentDelay = 1000L
val delayFactor = 2
doLongRunningTask()
.flowOn(Dispatchers.Default)
.retry(retries = 3) { cause ->
if (cause is IOException) {
delay(currentDelay)
currentDelay = (currentDelay * delayFactor)
return@retry true
} else {
return@retry false
}
}
.catch {
// error
}
.collect {
// success
}
}

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:
compileOnly "com.android.tools.lint:lint-api:$androidToolsVersion"
compileOnly "com.android.tools.lint:lint-checks:$androidToolsVersion"

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

  • 之后创建自定义规则. 每个lint check的实现都叫一个detector. 需要继承Detector, 并且利用Scanners来做扫描. 报告错误需要定义Issue. 还可以创建LintFx, 作为quick fix.
class ImageViewUsageDetector : LayoutDetector() {

   // Applicable elements

    override fun visitElement(context: XmlContext, element: Element) {
context.report(
issue = ISSUE,
location = context.getElementLocation(element),
message = REPORT_MESSAGE,
quickfixData = computeQuickFix()
)
} private fun computeQuickFix(): LintFix {
return LintFix.create()
.replace().text(SdkConstants.IMAGE_VIEW)
.with(TINTED_IMAGE_VIEW)
.build()
} // Issue, implementation, and other constants }
  • 然后把定义好的自定义规则注册.
class Registry: IssueRegistry() {

    override val issues: List<Issue>
get() = listOf(ImageViewUsageDetector.ISSUE) override val api: Int = CURRENT_API }
  • 创建入口, 在build.gradle文件中:

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

android { // Configurations above
lintOptions {
lintConfig file('../analysis/lint/lint.xml')
htmlOutput file("$project.buildDir/reports/lint/lint-reports.html")
xmlOutput file("$project.buildDir/reports/lint/lint-reports.xml")
abortOnError false
}
//Configurations below
} dependencies {
// Dependencies above // Include custom lint module as a lintCheck
lintChecks project(":custom-lint") // Dependencies below
}

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:

private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!! override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = ResultProfileBinding.inflate(inflater, container, false)
val view = binding.root
return view
} override fun onDestroyView() {
super.onDestroyView()
_binding = null
}

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

private val binding: FragmentFirstBinding by viewBinding()

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

class FirstFragment : Fragment(R.layout.fragment_first) {

  private val binding: FragmentFirstBinding by viewBinding()

  override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// Any code we used to do in onCreateView can go here instead
}
}

冷知识: DataBinding实现了ViewBinding.

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. ORACLE表与表联接的几种方式

    三大表与表联接方式 1.NESTED LOOPS 嵌套循环 2.HASH JOIN 哈希联接 3.SORT MERGE 排序合并联接 1.NESTED LOOPS  嵌套循环 嵌套循环的本质是将外部数 ...

  2. .Net Core 实体生成器

    实体生成器是什么? 实体生成器的功能就是自动将数据库中的表以及字段 转化成我们 高级编程语言中的实体类. 我们为什么要用实体生成器 在.net core开发环境下,我们可以使用efcore这个orm来 ...

  3. thread-01

    // 8:15 AM/09/28/2017 #pragma once #include <iostream> // std::cout #include <thread> // ...

  4. asp.net 远程模型验证

    有这样一些场景,我们需要模型验证,某些字段不允许重复,但是又不希望在数据访问层增加一堆额外逻辑判断.我们需要数据访问层简洁,这种模型验证在进去Action之前,验证不通过直接告诉前端. 一个特性,继承 ...

  5. 021_go语言中的异常处理

    代码演示 package main import ( "errors" "fmt" ) // Go语言里面约定错误代码是函数的最后一个返回值, // 并且类型是 ...

  6. Java基础高级篇 NIO

    nio模型与io模型的对比 netty 是什么 怎么使用

  7. Spring Cloud 之服务注册中心高可用

    服务注册中心高可用 服务注册中心 eureka-server 高可用实施 版本 Spring Boot 版本 # Spring Boot 版本: <parent> <groupId& ...

  8. Java Filter过滤器(拦截路径的配置+拦截方式的配置+生命周期+多个过滤器的先后执行顺序)

    Java Filter过滤器+Listen监听器 啥是过滤器 顾名思义即过滤掉一些东西,比如我们经历的高考中考都是过滤器,他过滤掉一些在学习这一方面不是很好的人,而那些成绩好的人则升入高中,大学. 但 ...

  9. Go 语言中,有时 nil 并不是一个 nil

    今天,我遇到了一个 Go FAQ.首先,作为一个小小的 Go 语言测验,看看您是否在 Go playground 中运行该程序之前就能推断出它应该打印出的内容(我已经将程序放在侧边栏中,以防它在 Go ...

  10. 树堆(Treap)学习笔记 2020.8.12

    如果一棵二叉排序树的节点插入的顺序是随机的,那么这样建立的二叉排序树在大多数情况下是平衡的,可以证明,其高度期望值为 \(O( \log_2 n )\).即使存在一些极端情况,但是这种情况发生的概率很 ...