2020-07-8 ARTS

ARTS1

A

调整数组顺序使奇数位于偶数前面
双指针解法。头尾各一个指针,头指针遇到的偶数和尾指针遇到的奇数,两个数字的位置互换。
题解思路比较简单,但是判断奇数和偶数可以使用与 1 按位与 结果是否为 1 来判断,作为计算的一种优化。这个做题时没想到。然后搜了一下运算优化的文章(像 【算法】位运算与优化这种 ),看了下其他的运算优化方式。

R

Kotlin Clean Architecture,又是一个代码架构方案,能有多好用,只能试试才能知道。

T

发现 LeakCannery 发现内存泄漏后,给引用链的时候,给不出 JNI 层导致的内存泄漏的引用链,但是它能发现 JNI 导致的泄漏。

S

最近股市挺热,分享个文章,大家还是要理性一点。https://mp.weixin.qq.com/s/OhuNId4NoaiD-kZpzVJ1Mw

ARTS2(补一周)

A

206. 反转链表 也是双指针,循环一遍就 ok。
21. 合并两个有序链表。简单题,思路也很简单,主要的时间是把代码写完善和优雅一点,

R

看了两个周的 sentry 使用文档,就是个用户手册,没啥好讲的。但是有一个东西比较有意思,关于 ELF 格式的 debug info files 说明,有些干货在里面。

T

  1. 一直苦于 Linux 命令行光标移动和内容删改效率低,从大佬那里学习了一下,还是有很多快捷键的。类似这种 Linux 命令行快捷键,之前居然没有留意过。
  2. 使用文档协作工具还是要留意是否支持 markdown 语法(现在想想一般应该都会支持)。傻乎乎的用了石墨好久,才发现它可以用 markdown 语法直接写内容。
  3. 接上回说 leakcannery 的泄露引用链少了 native 的部分。但是用 haha 库试了一下,发现它其实能够找到 JNI 层的 GC root,leakannery 其实就是做了个所有根节点到泄露 activity reference 的广度优先遍历,给出引用链最短的一个链路,为什么 leakcannery 没有 native 的 refe,还没细看。
    后来使用最新版本的 leakcannery 试了下,它能给出是 globle reference 引用了 activity,但 globle reference 的名称信息没有。

S

空白,最近没看到想分享的东西。

ARTS3

A

二叉搜索树的后序遍历序列
难度中等。判断一个数组是否是二叉搜索树的后序遍历序列。需要先找到二叉搜索树后序遍历结果的特点:按最右侧的值可以把数组划分成两部分,前一部分数字都小于最右侧值,后一部分数字都大于最右侧的值。划分出的两部分依然符合这个特点。然后是码代码实现递归判断数组是否符合上述规律。代码写的没有答案简洁。

R

7 Quick Kotlin Tips for Android Developers
kotlin 相对 java 的简单写法。有两个之前没用过的 tips。

交换两个数的值:
a = b.also { b = a }

check 条件 返回 IllegalArgumentException 异常
require(n>=0){"error message"}

list map
val nameList = persionList.map{persion -> persion,name}
 => val nameList = persionList.map(Persion::name)

T

consumerProguard,aar 提供自己的混淆规则,集成进项目打包的时候会对整个项目应用这个规则。

S

根据 Probe:Android线上OOM问题定位组件matrixhaha 来学习内存 dump 、剪裁与分析。
从代码结合文章,看内存 hprof 的格式:

image.png

image.png

// package com.tencent.matrix.resource.hproflib.HprofReader
    public void accept(HprofVisitor hv) throws IOException {
        acceptHeader(hv);
        acceptRecord(hv);
        hv.visitEnd();
    }

    private void acceptHeader(HprofVisitor hv) throws IOException {
        final String text = IOUtil.readNullTerminatedString(mStreamIn);
        final int idSize = IOUtil.readBEInt(mStreamIn);
        if (idSize <= 0 || idSize >= (Integer.MAX_VALUE >> 1)) {
            throw new IOException("bad idSize: " + idSize);
        }
        final long timestamp = IOUtil.readBELong(mStreamIn);
        mIdSize = idSize;
        hv.visitHeader(text, idSize, timestamp);
    }

    private void acceptRecord(HprofVisitor hv) throws IOException {
        try {
            while (true) {
                final int tag = mStreamIn.read();
                final int timestamp = IOUtil.readBEInt(mStreamIn);
                final long length = IOUtil.readBEInt(mStreamIn) & 0x00000000FFFFFFFFL;
                switch (tag) {
                    case HprofConstants.RECORD_TAG_STRING:
                        acceptStringRecord(timestamp, length, hv);
                        break;
                    case HprofConstants.RECORD_TAG_LOAD_CLASS:
                        acceptLoadClassRecord(timestamp, length, hv);
                        break;
                    case HprofConstants.RECORD_TAG_STACK_FRAME:
                        acceptStackFrameRecord(timestamp, length, hv);
                        break;
                    case HprofConstants.RECORD_TAG_STACK_TRACE:
                        acceptStackTraceRecord(timestamp, length, hv);
                        break;
                    case HprofConstants.RECORD_TAG_HEAP_DUMP:
                    case HprofConstants.RECORD_TAG_HEAP_DUMP_SEGMENT:
                        acceptHeapDumpRecord(tag, timestamp, length, hv);
                        break;
                    case HprofConstants.RECORD_TAG_ALLOC_SITES:
                    case HprofConstants.RECORD_TAG_HEAP_SUMMARY:
                    case HprofConstants.RECORD_TAG_START_THREAD:
                    case HprofConstants.RECORD_TAG_END_THREAD:
                    case HprofConstants.RECORD_TAG_HEAP_DUMP_END:
                    case HprofConstants.RECORD_TAG_CPU_SAMPLES:
                    case HprofConstants.RECORD_TAG_CONTROL_SETTINGS:
                    case HprofConstants.RECORD_TAG_UNLOAD_CLASS:
                    case HprofConstants.RECORD_TAG_UNKNOWN:
                    default:
                        acceptUnconcernedRecord(tag, timestamp, length, hv);
                        break;
                }
            }
        } catch (EOFException ignored) {
            // Ignored.
        }
    }

  代码来自 matrix 一个名为 HprofReader 的类。是一个典型的访问者模式,在访问和处理比较复杂数据结构的存储文件,经常会见到。类用来解析 hprof 文件,解析出来的内容,交给传进来的 HprofVisitor 进行操作。
  可以看到它先访问了文件的头信息。取的内容很简单:一个 String(这里没有这个String 的长度信息,但是这个 String 以 0 结尾)、一个 int 值 idSize、一个时间戳。
  然后就是内容信息,每部分内容信息的开头是一个 tag 用来标识内容的类型,后面跟着的是时间戳和这部分内容的长度。根据不同的内容,进行不同的解析。
  具体内容类型的解析就不说了,看这个类的代码就能明白了。
  HAHA 库(2.0.3 版本)的解析类 HprofParser 与上述过程类似。

  内存剪裁、内存分析:留坑。需要考虑内存dump剪裁和分析的内存占用、时间消耗怎么优化。如果线上要 dump 内存上报,要剪去什么内容。剪掉内容后,内存占用大小、引用关系的信息是否还会保留,用于线上分析。看美团的操作更骚气一点,hook 了 dump 过程,生成过程中过滤掉之前想剪裁的内容。

ARTS4

A

剑指 Offer 36. 二叉搜索树与双向链表
只能说,好题。把二叉搜索树转换成排序的双向链表,原地转,不要申请额外的空间。
二叉搜索树的中序遍历就是从小到大排序的。做中序遍历,并且让当前遍历到的节点,left 指向 pre 节点,pre 节点的 right 指向当前节点,pre 指针移动到当前节点。这样操作会影响之后的遍历吗?答案是不会,只会改变已经遍历到的节点。

R

Handling Android runtime permissions in UI tests
这周在看测试,在做集成测试的时候,需求需要将单测跑在运行环境里面,并且能操作权限。上文是查找过程中看的文章。是在 ui 测试中怎么点掉权限申请弹窗。
AndroidTest 在 beta 版中已经提供了 PermissionRequester api 做这件事情,申请权限不再有弹窗。

T

做单测时有在真机上跑的需求时,可以用 AndroidTest。

S

本周没有内容分享。但分享一个还未处理好的问题:单测中的代码重复该如何对待?
前提:一个大佬的描述:写测试用例的目标是,即使没有技术背景也应该可以明白在做什么,沟通在测试中是第一位的。
问题:一个大佬的描述:当只有一个case的时候都很好,但是当有多个case时,就会出现很多重复的内容。
网上搜的问题:在单元测试中,重复代码是否更容易容忍
答案:不可以。重复在单测中也会导致难维护。并且如果重复还有一点不同,那么这点不同就会被忽略,让人变得难懂这些测试有什么不同。
解决:下周接着看。

ARTS5

A

剑指 Offer 38. 字符串的排列 求一个字符串里的字符能组成多少种不同的字符串,列举他们。
是回溯的典型题目。

R

T

IDEA 的 LiveTemplate。学习一下,有助于开发效率的提高。
速成文章链接 https://www.cnblogs.com/chenfangzhi/p/liveTemplate.html

S

这周分享一下 BDD 和 BDD 工具。
看了个文章感觉写的挺清楚的:探索 Android BDD 开发方法
BDD 工具:Cucumber
Cucumber 的使用分两部分:

非技术人员也能看的懂得场景和用例说明

  1. 使用中文
  2. 验证什么
  3. 测试用例
i技术人员的 TestCase 实现
  1. 与上张图里面的步骤说明一致
  2. 与上张图里面的步骤关键字一致。

Cucumber 规定了这两者的语法,并将这两者关联起来,转化需求和用例描述为可以执行的AndroidTest 形式的单测。执行 ./gradlew connectedCheck 就可以验证研发的业务实现了。

关于上周提到的单测代码重复和单测代码框架的问题,继续留坑。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342