写点什么

ARTS 打卡 Week 01

用户头像
teoking
关注
发布于: 2020 年 05 月 24 日
ARTS打卡Week 01

每周完成一个 ARTS:

Algorithm: 每周至少做一个 LeetCode 的算法题

Review: 阅读并点评至少一篇英文技术文章

Tips: 学习至少一个技术技巧

Share: 分享一篇有观点和思考的技术文章



Algorithm

// LC 64. Minimum Path Sum
public class MinimumPathSum {
// Recursion with memoization (计划递归)
// Runtime: O(mn)
// Space: O(mn)
public int minPathSum(int[][] grid) {
int m = grid.length;
if (m == 0) return 0;
int n = grid[0].length;
int[][] table = new int[m][n];
return walk(grid, table, n, m, m - 1, n - 1);
}
int walk(int[][] grid, int[][] table, int n, int m, int x, int y) {
// 起点
if (x == 0 && y == 0) {
return grid[x][y];
}
// 边界
if (x < 0 || y < 0) {
return Integer.MAX_VALUE;
}
// 已经找过的最小路径
if (table[x][y] > 0) {
return table[x][y];
}
// 当前位置最小path sum算法
// f(x, y) = grid[x][y] + min(f(x + 1, y) + f(x, y + 1))
table[x][y] = grid[x][y] + Math.min(walk(grid, table, n, m, x - 1, y),
walk(grid, table, n, m, x, y - 1));
return table[x][y];
}
// DP
// Runtime: O(mn)
// Space: O(1)
public int minPathSum2(int[][] grid) {
int m = grid.length;
if (m == 0) return 0;
int n = grid[0].length;
for (int i = 0; i < m; ++i) {
for (int j = 0; j < n; ++j) {
// 从(0, 0)开始
if (i == 0 && j == 0) continue;
// 处于第一列时,f(x, y) = f(x, y - 1) + f(x, y)
if (i == 0) {
grid[i][j] = grid[i][j - 1] + grid[i][j];
}
// 处于第一行, f(x, y) = f(x - 1, y) + f(x, y)
else if (j == 0) {
grid[i][j] = grid[i - 1][j] + grid[i][j];
}
// 普遍情况, f(x, y) = f(x, y) + min(f(x - 1, y), f(x, y - 1))
else {
grid[i][j] = grid[i][j] + Math.min(grid[i - 1][j], grid[i][j - 1]);
}
}
}
// 最终返回目标点值
return grid[m - 1][n - 1];
}
}



Review

Say no to BaseActivity and BaseFragment 阅读笔记



这篇文章首先提到一种Android app开发领域常见的问题:随着项目的发展,BaseActivity和BaseFragment会日益膨胀。

这会带来以下问题:

  • Virtual methods need to be added in order to tweak behavior. (需要添加虚方法来改变一些行为)

  • Many lifecycle methods need to be implemented. (需要实现很多生命周期方法)

  • We need slightly different behavior and base class doesn’t allow it, requiring changes. (仅需要一点行为变化,但base不支持的话,就需要改代码)

  • For each scenario, another tweak needs to be added to the base class. (做事靠tweak)



作者提出用Application.ActivityLifecycleCallbacksFragmentManager.FragmentLifecycleCallbacks,通过Composition(组合)来替代上述继承方案。



例如,一个统计组件就可以这么实现:

  1. 统计组件实现lifecycle callback

class AnalyticsCallbacks(
val analytics: Analytics
) : Application.ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) = analytics.activityCreated(activity)
override fun onActivityResumed(activity: Activity) = analytics.activityResumed(activity)
override fun onActivityPaused(activity: Activity) = analytics.activityPaused(activity)
override fun onActivityDestroyed(activity: Activity) = analytics.activityDestroyed(activity)
// Other methods are empty
}
  1. Application中注册

class App : Application()
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(analyticsCallbacks)
}
// ... other App code
}



与Dagger的配合这里先不讲了(对dagger不熟悉,后续有需要再来查看)。



onActivityResult()的例子就比较tweak了:



流程图是比较清晰了,思路是创建一个不可见的shadow activity, 来将onActivityResult()事件通知给全局的permission handler来处理,handler将事件callback给permission的请求方。



Review总结:

  1. 从工程的角度来讲,庞大的BaseActivity和BaseFragment的确是一些有(不)历(重)史(构)的安卓项目的通病。但如果项目经历过架构更迭,比如曾经过渡到MVVM或者DDD相关模式(记得infoq上有一篇网易新闻团队文章将过架构升级的事情),这个问题应该会不那么严重。

  2. 从设计的角度来讲,文章的确提供了很好的思路。通常情况下,组合比继承更优(尤其要安卓四大组件,因为有很多生命周期方法,会使事情变得复杂)。对于一个组件来说,关心哪些生命周期方法应该由自己说了算,但如果Fragment或Activity使用了很多组件,那么就会造成复写后的生命周期方法臃肿不堪。而通过lifecycle callback,就可以完全将这些组装代码分离到组件自己的实现中,真正实现组件自己说了算。



Tip

通过grafika项目中的Spirite2d实现图片通过OpenGL ES显示

具体实现可参考我实现的例子:DrawImageSprite2dViewModel.kt



Share

webrtc团队带来的演讲:Google WebRTC project update & Stadia review

  1. Uberti讲Cloud Game和Streaming Service的区别 (10:45

  • Interactive, not passive

  • buffering is unacceptable

  • caching is not possible

  • incurring packet loss or retransmission must be avoided



  1. 关于latency一段的解释,很是精彩(10:46







发布于: 2020 年 05 月 24 日阅读数: 120
用户头像

teoking

关注

Monkey plays software. 2018.11.28 加入

程序员。目前主要从事Android和iOS开发。

评论

发布
暂无评论
ARTS打卡Week 01