美文网首页
2020-07-8 ARTS

2020-07-8 ARTS

作者: 不仅仅是代码 | 来源:发表于2020-07-06 21:24 被阅读0次

    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 就可以验证研发的业务实现了。

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

    相关文章

      网友评论

          本文标题:2020-07-8 ARTS

          本文链接:https://www.haomeiwen.com/subject/ejagqktx.html