Skip to content
Ider

沉淀我所学习,累积我所见闻,分享我所体验

Primary Navigation Menu
Menu
  • Home
  • About Ider
    • Who Ider?
    • Why Ider?
    • How Ider?
    • Where Ider?
    • What Ider?

Mobile Development(移动开发)

2021-01-14
14 January
On January 14, 2021
In Design Patterns(设计模式), English Posts(英文写作), Knowledge Base(心得笔库), Mobile Development(移动开发), Software Engineering(软件工程)

ProtoBuf 2.0 method count optimization for android development

The Protocol Buffer library was not initially built for Android, it just turned out to have a Java version to be used in Android, but it’s not optimized for Android apps, for example: it doesn’t consider the method count limit in Android.

So, in this article, I’d like to share some work I found specifically on Protocol Buffer Version 2 that can reduce the method count. If your app is also heavily relying on Protocol Buffer, I hope these approaches are useful for you too.

General Approaches

1. Use Protocol Buffer Java Lite Runtime

Just as the name indicates, the dependency library is much smaller than the regular Protocol Buffer Java runtime, the generated code is also much slimmer. However, the APIs are compatible between those two versions, so the call sites would not be affected when changing the library.

2. Don’t use <Message>OrBuilder interface

For each Protocol Buffer message definition in .proto file, the Protocol Buffer compiler generates an interface named <Message>OrBuilder (<Message> is the name defined in .proto file). This interface would be implemented by the concrete <Message> class and the corresponding Builder.

It might be attractive to use it as a variable type thereby you can depend on abstractions to not concrete classes. But calling methods on Java interface would make Dex take count of those methods.

In reality, every place can directly use either <Message> or Builder, then the optimization tool (like R8, ProGuard) can safely remove the methods declared on the interface.

Special Tricks

Protocol Buffer Java Lite is very good, but if I open the magic box of generated Java classes, I notice it’s still not optimal for Android. There are a couple places I could modify to make it more effective for Android applications.

Instead of copying the Java files and making the change, which is error prone when engineers update the .proto file, I created a script to automate the job. Just add the execution of this script at the end of the Protocol Buffer gradle task, so it works just as a complement of Protocol Buffer code generation process.

[codesyntax lang=”groovy” lines=”normal”]

protobuf {
  protoc {
    artifact = 'com.google.protobuf:protoc:3.7.0'
  }
  plugins {
    javalite {
      artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
    }
  }
  generateProtoTasks {
    all().each { task ->
      task.builtins {
        remove java
      }
      task.plugins {
        javalite { }
      }

      // `getOutputDir()` can only be read during configuration, 
      // so it’s out of action block
      def outputDir = task.getOutputDir(task.plugins[0])
      task.doLast {
          exec {
              commandLine file('protobuf-optimizer.py')
              args outputDir
          }
      }    
    }
  }
}

[/codesyntax]

In the script, I have made the following modification on generated java code.

1. Change the modifier of Builder constructor from private to package

Simply running the sample addressbook.proto from Protocol Buffer tutorial side, you would get a class like the following snippet:

[codesyntax lang=”java” lines=”normal”]

public static final class Person {
    private Person() {}

    protected final Object dynamicMethod(
            com.google.protobuf.GeneratedMessageLite.MethodToInvoke method,
            Object arg0, Object arg1) {
        switch (method) {
            case NEW_BUILDER: {
                return new Builder();
            }
        }
    }

    public static final class Builder {
        private Builder() {}
    }

}

[/codesyntax]

When analyzing the APK file, we could would find some synthetic classes and methods:

This is because the outer class is accessing the private constructor of the inner class. The generated synthetic class would contribute an extra constructor to the Dex file. Therefore, by simply removing the private from Builder(), you can remove such classes and methods.
Read More →

2020-03-12
12 March
On March 12, 2020
In Data Structures(数据结构), Knowledge Base(心得笔库), Language Tips(语言初试), Mobile Development(移动开发)

基础数据类型的包装类的内存大小

谈到 Java 的基础数据类型(Primitive Data Types),可以找到很多关于其种类以及内存大小的文章。基础数据类型对应的包装类(Wrapper Classes)也会介绍自动装箱(Autoboxing)和拆箱(Unboxing),以及带来的效率上的影响。但可能是因为Java一般所使用的环境都有比较充足的内存,似乎从来没有人讨论过每种包装类所占的内存大小以及对内存溢出可能造成的影响。

到了 Android 应用程序开发领域,由于设备硬件本身以及系统对各个程序在资源使用上的约束,就会出现很多特别的使用习惯,比如推荐使用Typedef来替代枚举类型(enum)来减少内存使用和方法数。因此关于基础数据类型的包装类所占内存大小就值得写篇博客来研究一下。

包装类所占内存大小

网上我找了很多计算类内存大小的方法,但是既然我是 Android 工程师,我就用 Android Studio 提供的 Memory Profiler 来查看内存使用情况

下边就是我用来做内存检查的类,它包含了所有基础数据类型和对于的包类型

[codesyntax lang=”java” lines=”normal”]

public class Primitives {
  boolean pBoolean;
  byte pByte;
  char pChar;
  double pDouble;
  float pFloat;
  int pInt;
  long pLong;
  short pShort;

  Boolean cBoolean;
  Byte cByte;
  Character cChar;
  Double cDouble;
  Float cFloat;
  Integer cInt;
  Long cLong;
  Short cShort;

  public Primitives() {}

  public Primitives(Void v) {
    cBoolean = false;
    cByte = 0;
    cChar = '\0';
    cDouble = 0.0;
    cFloat = 0.0f;
    cInt = 0;
    cLong = 0L;
    cShort = 0;
  }
}

[/codesyntax]

接着在 MainActivity 中创建两个 Primitives 类的字段:一个没有初始化对象类型,一个将所有对象类型初始化成默认值。然后运行程序,在 Android Studio 中打开 Profiler 查看内存时”Dump Java heap” 就可以看到这两个 Primitives 对象内存使用情况

从图中的结果可以看出如果对象的值是 null,那他们是不占用空间。在这一点上看,如果字段大部分时间都存的是空值或者以空值指代默认值,那相对比总是会被赋予默认值的基础数据类型在内存使用方面要好一些。

对于包装类,它们都比其对应基础数据类型要占用更多的内存空。仔细对比不难计算出他们的差别都是 8 bytes,正好是一个普通 Object 实例的大小。这也证明的包装类只是对基础数据类型的简单包装。

基础数据类型 包装类型
类型 大小 类型 大小
boolean 1 byte Boolean 9 bytes
byte 1 byte Byte 9 bytes
char 2 bytes Character 10 bytes
double 8 bytes Double 16 bytes
float 4 bytes Float 12 bytes
int 4 bytes Integer 12 bytes
long 8 bytes Long 16 bytes
short 2 bytes Short 10 bytes

所以,使用包装类不仅会有自动装箱和拆箱产生的效率上的影响,对内存的使用也有很大的影响。而 Android 的内存又是稀缺资源,所以 Android 库里多了特殊的数据类型来优化内存的使用,比如 SparseArray 替换以 int 为主键的 HashMap。
Read More →

2019-08-29
29 August
On August 29, 2019
In Data Structures(数据结构), Knowledge Base(心得笔库), Mobile Development(移动开发), Software Engineering(软件工程)

Gradle android-library 的各种坑

软件开发随着项目越来越大,我们会开始拆封出多个子项目(sub-project)或者库(library)来更好地独立维护。Android开发也不例外,我们也会需要创建各种库。如果使用Android Studio和Gradle,他们为我们提供了便捷的方式来创建libray。但是他们也带来了不少的维护问题,本文就来讲讲android-library里的坑来帮助大家避开。

android-library v.s. java-library

对于普通Android手机项目,我们有创建两种不同的Library可以选用: android-library 和 java-library

它们的gradle文件内容分别如下

[codesyntax lang=”groovy” lines=”normal” highlight_lines=”1″]

apply plugin: 'com.android.library'

android {
    // ...
}

dependencies {
    // ...
}

[/codesyntax]

[codesyntax lang=”groovy” lines=”normal” highlight_lines=”1″]

apply plugin: 'java-library'

sourceCompatibility = "7"
targetCompatibility = "7"

dependencies {
    // ...
}

[/codesyntax]

两种库在定义上的根本差别其实就是不同gradle plugin的使用。另一个小的差别就是android-library需要有一个 AndroidManifest.xml 文件,但它可以简单到只有一行内容(其中package的值通常是文件夹的路径)

[codesyntax lang=”xml” lines=”normal”]

<manifest package="com.ider.android.library" />

[/codesyntax]

使用上他们有一些差异,这些差异也是我们决定使用哪种Library的标准:

  • android-library 可以使用 Android API(比如Activity, Service等等),java-library 则不能使用
  • android-library 可以编译android资源文件(resources files),java-library 则无视这样内容
  • android-library 编译出 arr 文件,java-library编译出 jar 文件(本质上他们都是 zip 文件)
  • android-library 的配置可以包含各种编译类型(build variants)来控制,java-library没有那个复杂
  • android-library 可以依赖于另一个android-library 或者 java-library, java-library只能依赖于java-library而不能依赖于android-library

总体而言 android-library 基本是 java-library 的一个超集, 但 android-library 比 java-libray 使用起来要更加复杂一些。从上边的对比来看,对于Android的项目,因为我们不确定什么时候会需要调用 Android 的API,或者定义一下 Android 的资源内容。再者最后一条的约束也决定了创建的 java-library 要保证在整个依赖树(dependency tree)上要在接近叶子节点的位置。所以不如优先选择创建android-library,以免掉入之后改 build.gradle 的坑中。
Read More →

2018-10-29
29 October
On October 29, 2018
In IT Products(数码产品), Mobile Development(移动开发), Tangential Speech(漫话杂谈)

Google Pixel 3 XL 用户体验

上周收到了Pixel 3 XL,简单上手使用之后,最直接的感受是比较失望:

  • 丑陋的刘海造型,而且特别的厚,大部分应用都还没有对其做适应,所以状态条看起来非常不协调
  • 背后的材料变成了玻璃的,没有了原来铝材料的质感好
  • 新的导航手势也不是很舒适,特别是上划两次才能打开应用列表,因为用上划一次来取代了最近使用应用列表
  • 扬声器非常的差,播放声音时背后震动很强烈,声音也闷得好像是老式收音机
  • 跟Pixel 2 XL相比没有特别大的提升

值得点赞的地方可能就是:相机拍摄的照片更加清晰了,特别是前置摄像头带了两个摄像头,拍人像更好看了;还有那 Nexus 系列就有的到了 Pixel 前两代却去掉了的无线充电功能。

对于刘海就特别想吐槽,这部分跟状态栏重叠,所以会导致能显示的通知消息比原来少,非常的讨厌。对于有些应用将状态栏改成其他颜色时,刘海就会特别明显,但是如果进行屏幕截图,刘海的黑色部分又会被自动补全,造成所见影像和生成的图片不一致,非常的抓狂。
要想去除刘海,就需要打开“开发者选项(Developers Options)”来设置,但是真缺了那状态栏的一点空间又觉得挺可惜的。最搞笑的是“Double Cutout”,对称的上下两个刘海,可惜截图是看不出来的。

应用方便,对于 Pixel 3 和 Pixel 3 XL 独享的 Screening Call 表示赞叹,可以过滤掉不少垃圾电话。有些不足的地方是翻译过来的文字必须当场阅读,电话挂断之后就会消失,如果能自动把内容转到Google Voice的留言信息保存起来就更好了。

另外,非常喜欢 Google 还在 beta 测试中的 Digital Wellbeing 的服务,可以看到每天在各种应用上浪费的时间。

同时设置时间来约束使用时长,当天的配额用完后,系统就会应用启动图标变灰并且不能再使用。比如我把 YouTube 的时间设置成了30分钟来防止自己沉迷,但实际是经常我就去设置那边把约束时间去掉,然后静静地在 YouTube 上度过了3个小时。所以本身的自制力才是关键。
希望以后这个服务可以推出更多功能,比如这些功能都是我希望其提供的:导出数据;家长约束并设置不同密码(这样就可以交给太太来管制我);桌面图标小插件;更方便的访问入口。

 

最后,放两张Pixel XL系列的照片(比较讽刺的是照片使用太太的 iPhone X 拍摄的),以及三款手机的规格对比。

Pixel 3 XL Pixel 2 XL Pixel XL
Height 158 mm (6.2 inches) 158 mm (6.2 inches) 154.7 mm (6 inches)
Width 76.7 mm (3.0 inches) 76.7 mm (3.0 inches) 75.7 mm (2.9 inches)
Thickness 7.9 mm (0.3 inches) 7.9 mm (0.3 inches) 8.5 mm (0.3 inches)
Weight 184 grams (6.49 ounces) 175 grams (6.2 ounces) 168 grams (5.93 ounces)
Screen Size 160 mm (6.3 inches) 152.4 mm (6.0 inches) 139.7 mm (5.5 inches)
Screen resolution 2,960 x 1,440 pixels 2,880 x 1,440 pixels 2,560 x 1,440 pixels
Pixel Density 523 ppi 538 ppi 534 ppi
Screen To Body Ratio 83.49% 76.71% 71.04%
RAM 4 GB 4 GB 4 GB
Storage space 64 GB, 128 GB 64 GB, 128GB 32 GB, 128 GB
Processor Qualcomm Snapdragon 845 Qualcomm Snapdragon 835 Qualcomm Snapdragon 821
Graphics Adreno 630 Adreno 540 Adreno 530
Camera 12MP rear, dual 8MP lenses front 12MP rear, 8MP front 12MP rear, 8MP front
Colors Just Black, Clearly White, Not Pink Just Black, Black and White Very Silver, Quite Black, Really Blue
Release date October 9, 2018 October 4, 2017 October 4, 2016
2017-05-03
03 May
On May 3, 2017
In Knowledge Base(心得笔库), Language Tips(语言初试), Mobile Development(移动开发)

Android编译工具Gradle和Buck使用对比

前面介绍了Gradle和BUCK两个编译工具的基本概念,本篇文章再来说说日常使用情况。本文不涉及配置方面的使用,毕竟大多时候配置工作是不重复的任务,具体操作可参见官方文档。这里主要讲讲日常工作会用到的使用两个工具编译,安装等操作的不同体验。

指令(Command)

指令操作是程序自动话的先决条件,两者都是基于指令来执行编译任务。其主指令分别为./gradlew和buck,然后调用子指令来执行相应的操作。
Read More →

2017-02-27
27 February
On February 27, 2017
In Knowledge Base(心得笔库), Language Tips(语言初试), Mobile Development(移动开发)

Android编译工具Gradle和Buck浅对比

在Twitter工作的那两年,我学习了Gradle编译Android,了解了很多Gradle的配置;在Facebook的一年里我又学习了Buck编译工具,跟Buck的开发人员有过交流。现在市场上主流的Android编译工具还是Google官方推行的Gradle,Github上很多Android开源项目也会带上Gradle文件,只有很少的项目会选用Buck。

本文就来分享一些我对两者的使用体验。不过我对编译工具的使用还停留在当做配置文件的阶段,还没有到达当做开发工具做深入自定义的程度,也没有足够的经验来总结说Gradle和Buck两个编译工具到底哪个比另一个更好,所以只能描述一些比较浅显的表层对比。

语言(Language)

Gradle使用的语言是Groovy。为了能更好的了解Gradle,我曾特尝试学习了Groovy,它算是Java的超集,可以跟Java无缝结合,只不过Groovy加入了诸多丰富的元素来弥补Java的不足。其中一点就是Groovy的闭包形式似乎又结合了JavaScript里的概念,却又不是非常成熟,当年学习的时候没有特别能领悟其中的奥秘就中途放弃了。另一方面,Gradle实际上是Groovy提供的“领域特定语言(Domain-specific language, DSL)”,然后用Groovy的语法解析去执行。然后再读Gradle的文档了解提供的特定API,内容无比繁多。好在Google总结了Android开发需要的内容,平时也只要复制粘贴必要的内容即可。

Buck使用的语言是Python。可以在BUCK文件里书写任何Python指令来执行,比如动态配置源码范围等等。但最长使用的还是对Buck规则做一层包装来进行自定义规则。不过通过跟Buck的开发人员的交流,Buck实际上是用Java开发出来的,在编译时开启了Python环境来编译Buck。

 

对比Groovy和Python,前者几乎没有听到过其他的应用,深入学习不会带来其他好处,后者应用广泛,但是在Android开发上也不会有更多帮助。再者,要使用Gradle和Buck这两个编译工具,也并不需要对相应的两门语言有深入的理解,只要掌握基本使用即可。

模块(Module)

这里的模块是指Intellij的项目模块,是为了更好的组织、测试、重用而创建的独立单元。每个模块都有它的属性:比如主模块是应用程序,此外我们会创建资源模块,Java库模块,Android库模块等等。当开发多个应用程序时,就可以引入部分模块来重用。
Read More →

2015-11-26
26 November
On November 26, 2015
In English Posts(英文写作), Mobile Development(移动开发)

2015 Android Dev Summit Schedule and Videos

ads
Here is the full schedule of Android Dev Summit. If you missed the live stream, you can find the YouTube Play List here. You can find the video link for each session from the title in the following schedule table as well.
The table also contains the speakers of each session, and their Twitter accounts are attached to their names. If you like to know more about Android Development, you can follow them and @AndroidDev.

Day 1

9:05am – 9:45am

Keynote

Dave Burke & Stephanie Saad Cuthbertson

9:45am – 10:30am

Android Application Architecture

Yigit Boyar & Adam Powell

10:30am – 11:00am Coffee Break
11:00am – 11:45am

Respecting User Attention: Notification Best Practices

Chris Wren

Secrets To App & Game Success On Google Play

Brian Quimby & Andreas Preuer

11:45am – 12:30pm

Keep It Secret, Keep It Safe

Chad Brubaker

Android Textual Layout

Raph Levien

12:30pm – 1:30pm Lunch
1:30pm – 2:15pm

RecyclerView Animations And Behind The Scenes

Chet Haase & Yigit Boyar

2:15pm – 3:00pm

Support Library: Guts And Glory

Chris Banes & Adam Powell

3:00pm – 3:30pm Office Hours
3:30pm – 4:15pm

“Mother, May I?” Asking For Permissions

Svet Ganov & Jeff Sharkey

4:15pm – 5:00pm

Framework Fireside Chat

Hosted By Dan Galpin

Read More →

2015-11-25
25 November
On November 25, 2015
In Mobile Development(移动开发)

2015 Android Dev Summit第二天

今天的演讲主要是关于Android开发工具,其中又以Android Studio 2.0作为重点介绍项目。
android-studio
(上图是唯一一张不是来自会场的照片)

9:00演讲正式开始,基本是昨天开场介绍Android Studio 2.0和新的Emulator的加长版,但同时也对Instant Run的原理做了简单的介绍。不管怎样Android Studio 2.0都是很值得期待的,而且Google已经抛弃Eclipse for Android很久了,所以赶紧转到Android Studio吧。
IMG_20151124_090044

之后跟昨天一样也是两个演讲同时进行,一个关于新出的Data Binding。我则去了另一个关于User Identity方面,不过这个演讲只是介绍了怎么用Google Service提供的Google Account来作为登录账号。更多的API的介绍和使用还得自行网上搜索。然后听了关于Android Build System的演讲,不过没有什么Demo的过程。
Read More →

2015-11-24
24 November
On November 24, 2015
In Mobile Development(移动开发)

2015 Android Dev Summit第一天

今年的Google I/O没有抽到票,不能到现场参加。不过11月举行的Android Dev Summit的票是先到先得的方式,所以早早的提交了注册。今天终于有机会当面跟Android系统的设计开发者们进行交流,还能见到来自各个公司的Android工程师,跟他们讨论Android开发中碰到的问题。
ads

演讲一开始就给大家一个惊喜:Android Studio 2.0
android-studio
Read More →

2015-10-08
08 October
On October 8, 2015
In Knowledge Base(心得笔库), Mobile Development(移动开发)

Style在Android中的继承关系

Android的Styles(样式)和Themes(主题)非常类似Web开发里的CSS,方便开发者将页面内容和布局呈现分开。Style和Theme在Android里的定义方式是完全一样的,两者只是概念上的区别:Style作用在单个视图或控件上,而Theme用于Activity或整个应用程序。由于作用范围的不同,Theme也就需要比Style包含更多的定义属性值的项目(item)。不过本文,我将Style和Theme都归为Style来称呼。

Android的Style和Web的CSS相比,有一个缺陷就是只能针对一个对象只能通过android:theme="@style/AppTheme"或style="@style/MyStyle"指定一个值。而CSS则可以通过class属性在DOM元素上定义多个样式来达到组合的效果。不过Style也有CSS没有的功能,那就是继承(Inheritance)。(当然CSS通过LESS和SASS这些工具也获得继承的能力。)
Read More →

Posts pagination

1 2 3 Next
Facebook
Twitter
LinkedIn
RSS
ZhiHu

Recent Posts

  • 三年居家工作感受
  • Pixel Watch智能手表和Pixel 5, 6 Pro 及 7 Pro手机
  • 我拥有过的无线耳机
  • 毕业工作一个月,我差点被开除
  • 我拥有过的移动硬盘
  • ProtoBuf 2.0 method count optimization for android development
  • 面过100场行为面试后

Categories

  • Algorithm Analysis(算法分析)
  • Article Collection(聚宝收藏)
  • Data Structures(数据结构)
  • Design Patterns(设计模式)
  • English Posts(英文写作)
  • Front Interface(界面构想)
  • IT Products(数码产品)
  • Knowledge Base(心得笔库)
  • Language Tips(语言初试)
  • Mathematical Theory(数学理论)
  • Mobile Development(移动开发)
  • Programming Life(程序人生)
  • Reading Notes(阅而后知)
  • Software Engineering(软件工程)
  • Special Tricks(奇技妙招)
  • Tangential Speech(漫话杂谈)

Tags

Aero Android API Bash Binary Search Bitwise Operation Book C/C++ Career Chrome Conference CSS Debug Device DOM Extension Framework Game Gradle Hearthstone HTML Initialization Intellij Interview iOS Java JavaScript jQuery Keyword Language Issues Mac Microsoft Mobile Modifier Objective-C PHP Principle Reference Regular Expression Static String Tools Tutorial UI XML

Blogroll

  • Ahmed's Blog
  • Gert Lombard's Blog
  • Gordon Luk
  • Jack & Allison
  • 开发部落

Archives

Designed using Chromatic. Powered by WordPress.