Android开发时,那些相见恨晚的工具或网站!

本文来我在知乎话题Android开发时你遇到过什么相见恨晚的工具或网站?下的回答!

Android开发时你遇到过什么相见恨晚的工具或网站?

在实际Android开发过程确实会有很多相见恨晚的工具或网站出现,下面是我自己的一些分享。

源码网站

https://github.com/googlesamples

Android系统每次推出一些新特性,Google都会写一些Demo放在Github上,对于想要了解新特性怎么玩的同学,肯定不能错过它。

https://www.codota.com/

如果你不知道一个Android的类怎么用,可以在Codota上面快速的找到很多不错的示例代码。

https://android-arsenal.com/

你是否还在为找不到合适的开源库而苦恼,Android Arsenal这个网站已经帮你做了一定的分类,可以帮你提高不少效率。

https://android.googlesource.com/

Android所有的源代码都在这里,只需找到对应想要的模块,用Git克隆下来即可。比如,我想要的framework代码

http://androidxref.com/

克隆Android一个模块的代码量是很多的,有时候我只想要几个类的代码怎么办?AndroidXRef这个网站可以让你单独搜索某个类,要哪几个下载哪几个即可。

http://grepcode.com/

除了AndroidXRef可以查看某个类的源代码外,GrepCode同样也能做到。而且GrepCode不限于Android的源码,这里也推荐一下。

源码分析

源码分析的网站很多,这里举几个比较经典的网站。

继续阅读全文 »

Android应用安全风险与防范

近段时间在做Android应用安全方面的功课,本文进行简单梳理方便以后Review,有错误和遗漏之处还请大家指出。

代码混淆

Android开发除了部分功能采用C/C++编码外,其余主要都是采用Java进行编码开发功能。Java应用非常容易被反编译,Android自然也不例外。只要利用apktool等类似的反编译工具,就可以通过安装包获取源代码。Google为了保护开发者的知识产权,为Android提供了ProGuard混淆方案,以增加反编译后源码阅读,但对于Android开发老司机和逆向工程师来说,解读还原出源代码只是时间问题。

ProGuard是针对Java应用的保护,并不是专门针对Android应用的,Android虽然使用Java开发,但是毕竟不是跑在JVM上,所以安装包结构和普通的Java应用还是区别多多。如果你对免费的ProGuard放心不下,可考虑试试付费的混淆方案DexGuard,除了拥有ProGuard的功能外,还包含资源混淆,字符串加密,类加密和dex文件分割等。

虽然代码混淆是最为基础的保护措施,不过国内仍有不少应用还是裸奔的,其中还包括一些大厂应用(此处不表)。

签名校验

Android黑产里面,有一个叫做二次打包,也称为重打包。即通过反编译正版应用后,可以获得smali源码,往其中注入代码或者修改相应业务逻辑后,再利用新的签名进行重新打包,并发布到应用市场去,很多无良开发者就是通过这种方式去破解一些付费应用或者往其中注入广告代码来获利。简单梳理一下重打包的基本流程:

  1. 对正版应用用apktool类逆向工具进行解包;
  2. 在某处地方注入smali代码;
  3. 利用IDE生成签名文件,再通过jarsigner进行签名;
  4. 上传应用市场;

为了与二次打包做对抗,可以在应用内的关键功能入口增加校验签名的检测,如果发现应用签名非正版,则强制关闭应用或者限制用户使用。加签名校验代码时,可以考虑:

继续阅读全文 »

Android应用瘦身,从18MB到12.5MB

最近在为我们开发的直播应用做 Android 端的安装包瘦身,花了大概一周的时间把安装包从 18MB 减小到了 12.5MB。原本完全可以优化到 10MB 之下,但由于其他原因的限制,所以目前阶段只到 12.5MB 为止。在此记录一下优化的思路和用到的工具,方便自己以后 Review ,有需要的童鞋也可供参考。

瘦身的目的

从目的导向来看,我们是不会无缘无故去做一件事情的,那我们对应用瘦身的目的是为了什么?答案是:提高下载转化率。什么是下载转化率?举个栗子:你的应用大小是 18MB ,有100个潜在用户想要去下载尝试使用,结果有20个用户嫌弃安装包太大直接扬长而去,有20个用户在等待下载的过程中取消下载,最终只有60个用户真正下载安装,那么应用的下载转化率就是 60/100 = 60% 。

简单的小结便是:安装包越小,用户下载等待的时间越短,对手机存储配置小的设备体验愈佳,应用的下载转化率也就越高。记得以前在腾讯大讲堂听微信大牛说过,微信第一个版本只有差不多 400KB ,瞬间膜拜。

安装包的组成

要对安装包做瘦身,首先需要了解安装包的组成结构,这里简单的梳理了一下组成各个部分及其作用:

其中,在安装包中占比较大的包括:dex文件、res文件夹、assets文件夹、lib文件夹以及resource.arsc文件。所以,接下来的瘦身优化就是让这些文件变小,以此达到瘦身的目的。

在 Android Studio 2.2.3 开始,就加入了浏览 APK 结构的功能,我们直接把安装包拖入 IDE ,就可以直接浏览其组成和对应大小,这样能够很方便的对比分析出每一步优化后的结果。

继续阅读全文 »

走过2016时,我成长些什么

时间过得超快,2016年转眼间就剩下那么几天,每到年尾都要对整整的一年做个总结,本文便是我的2016总结稿。

开发成长篇

一直以来,我主要都是从事 Android 开发这块的工作,对于后端或者 Web 端这块的,很多知识还停留在校园教科书式的时代。原本今年年初计划要重拾 Java 后端、 Web 端和 Python 这块,重新拓展一下自己的技术栈,但是上半年由于个人原因,导致原本想要开始的计划延迟了半年,下半年才开始执行计划,目前有闲暇时间都在看关于 Web 端和 Java 后端的,Python 这块至今还未动,这算是2016最大的遗憾了。

对于我来说,由于一直以来都是做客户端开发工作,很多问题的思考有一定程度局限在客户端视觉。有时候处在客户端的角度看待问题,得出来一些解决方案具有很多局限性。为了弥补自己思考方式上的短板,我在尝试从自己原本的圈子里走出来,站在不同的角度去看待业务需求的实现,这样得到的方案会更加具有可实践性。后端语言众多,为何选择 Java ?主要是当前 Java 是主流,外加 Android 开发也用的是 Java ,可以省去学新语法的时间。就学习来说,语言不是重点,相信如果打通了 Java 后端的任督二脉,换一种后端语言也可以很快入门上手。

随着 H5 、 HyBird 、 RN 、 Weex 、 微信小程序以及 Google 在 GDD 上提出的 Progressive Web AMPs 的出现,很多原本要原生 App 实现的功能,都交给了 Web 端的童鞋,甚至有些小公司,客户端的童鞋同时还要搞 Web 端的事。说实话,我对 Web 端的开发很久前就非常感兴趣,这些新技术的出现更加触发了我跃跃欲试的冲动。从实际应用场景来说,这种移动端的 Web 开发确实有很多很好的应用场景,但并不是所有的场景都适合使用。所以,我从来都不信 Web 即将取代原生应用的鬼话。站在开发者的角度来说,关注技术发展的趋势并学习一些新技术是非常必要的,而那些死守着自己一亩三分地的开发者是注定要被时代淘汰的。

继续阅读全文 »

Android应用内存泄漏的定位、分析与解决策略

最近一直在为项目做内存泄漏的优化工作,本文用于记录一些排查优化的思路和方案,以及介绍一些辅助工具。

什么是内存泄漏

对于不同的语言平台来说,进行标记回收内存的算法是不一样的,像 Android(Java)则采用 GC-Root 的标记回收算法。下面这张图就展示了 Android 内存的回收管理策略(图来自Google 2011的IO大会)

图中的每个圆节点代表对象的内存资源,箭头代表可达路径。当圆节点与 GC Roots 存在可达路径时,表示当前资源正被引用,虚拟机是无法对其进行回收的(如图中的黄色节点)。反过来,如果圆节点与 GC Roots 不存在可达路径,则意味着这块对象的内存资源不再被程序引用,系统虚拟机可以在 GC 过程中将其回收掉。

有了上面的内存回收的栗子,那么接下来就可以说说什么是内存泄漏了。从定义上讲,Android(Java)平台的内存泄漏是指没有用的对象资源任与GC-Root保持可达路径,导致系统无法进行回收。举一个最简单的栗子,我们在 Activity 的 onCreate 函数中注册一个广播接收者,但是在 onDestory 函数中并没有执行反注册,当 Activity 被 finish 掉时,Activity 对象已经走完了自身的生命周期,应该被资源回收释放掉,但由于没有反注册, 此时 Activity 和 GC-Root 间任然有可达路径存在,导致 Activity 虽然被销毁,但是所占用的内存资源却无法被回收掉。类似的栗子其实有很多,不一一例举了。对于 Android(Java)内存回收管理想要再深入了解的童鞋,可以看看下面资源:

泄漏的源头

了解完内存泄漏的理论知识后,再来归类一下内存泄漏的源头。这里我将其归位以下三类:

继续阅读全文 »

深入了解 Messenger 的实现细节

本文是阅读 Messenger 源码的一点记录,看这篇文章前,需要对 Android 的进程间通讯方式有所了解,不然可能会云里雾里。

从使用 Messenger 说起

Android 上实现 IPC (进程间通讯)的方式有好几种,其中有一种就是使用 AIDL 方式实现,对使用 AIDL 不了解的童鞋可以看下方的官方文档(需要梯子)。

https://developer.android.com/guide/components/aidl.html

对于使用 AIDL 方式通讯,其关键就在于创建 aidl 文件,系统会自动为 aidl 文件生成相应的 Java 类,其关键实现在于生成的 Java 类中。

系统提供了一个更方便我们进行 IPC 的类 —— Messenger,先来看看如何使用 Messenger(熟悉的童鞋完全可以跳过这一部分)。

  • 第一步:客户端进程创建两个 Messenger,一个 Sender ,一个 Receiver;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//客户端进程发消息给服务进程
private Messenger mSender;
//客户端进程接收服务进程回调
private Messenger mReceiver = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle data = msg.getData();
if (data != null) {
String response = data.getString("body");
Toast.makeText(MainActivity.this, response, Toast.LENGTH_SHORT).show();
}
}
});
  • 第二步:编写Service类,并需要在 AndroidManifest.xml 配置多进程;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class IPCService extends Service {
private Messenger messenger = new Messenger(new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
try {
Thread.sleep(2 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message response = Message.obtain();
Bundle data = new Bundle();
data.putString("body", "response");
response.setData(data);
try {
msg.replyTo.send(response);//回调客户端
} catch (RemoteException e) {
e.printStackTrace();
}
}
});
@Override
public IBinder onBind(Intent intent) {
return messenger.getBinder();//将Binder返回给请求绑定的进程
}
}
  • 第三步:绑定Service进程,并在 ServiceConnection 中初始化 Sender;

继续阅读全文 »

ScratchView:一步步打造万能的 Android 刮奖效果控件

我身边有一部分开发的小伙伴,存在着这样一种习惯。某一天,突然看到某一款 App 上有个很漂亮的自定义控件(动画)效果,就会绞尽脑子想办法去自己实现一发。当然,我自己也是属于这类型的骚年,看到某种效果就会手痒难耐琢磨着实现套路。个人觉得这是一种需求驱动进步的方法,当你绞尽脑子去实现自己想要的效果时,你就会发现你对 Android 自定义控件(动画)的知识体系认识越深,久而久之,自己也能轻松的造出各种控件(动画)效果。要是哪天,产品童鞋拿着个原型(或者对着某款 App )跟你讲:“XXXX,你看这个效果我们能不能实现?”,然后你瞥了一眼,胸有成竹丢回一句:“开玩笑,还有我实现不了的效果?”。想想心里是不是有点小激动?好了,差不多要说回正题了,这是我第一篇关于自定义控件的文章,以也会陆续穿插更新此类型的文章,希望大家能够喜欢。(偷偷剧透下,我下篇文章是关于性能优化的干货。当然我自己觉得很干货,希望到时候发出来不要打脸,哈哈哈!)

实现效果

说了这么多,还是先给大家看看最终的实现效果先

上面只是基本实现效果的一部分,你会看到下方还有很多其他控件,它们是用来干嘛的,接下来即将为你揭晓一切。

基本实现

日常生活中,我们对刮奖效果想必不会陌生,其原理就是通过在原有图案和文字上添加刮层来实现的。如果我们想看到刮层后面藏的图案和文字是什么,势必要通过刮开刮层才行。知道了这样的套路,就可以开始整理一下编码实现思路,然后愉快开干。

我一开始的实现思路是想通过重写 ImageView 和 TextView ,然后在分别用代码在图像和文字上添加图层,这样的话就能实现出效果了。然而回头一想,不对,这种实现存在的局限性比较大。如果照这种思路实现,那么刮层下面只能存在图片或者文字,如果产品经理要求同时存在图片和文字呢?要求存在两张图片呢?要求同时存在图片和文字,且文字放在图片的上(下、左、右)呢?…我们都知道,世界上最善变的除了妹纸的心,就是产品经理和他们的需求了。于是,便想出另外一种实现思路,直接继承 View 来实现一个刮层,让这个刮层和图片以及文字不产生任何依赖,再结合 FrameLayout 将刮层放置最上一层,刮层之下你想放多少图片文字,图片文字要怎么布局摆放都行。到此,思路明确,可以愉快的开始编码了。

继续阅读全文 »

知乎和简书的Android客户端夜间模式实现方式

说到夜间模式,在网上看到很多童鞋都说用什么什么框架来实现这个功能,然后仔细去看一下各个推荐的框架,发现其实都是动态换肤的,动态换肤可比夜间模式要复杂多了,未免大材小用了。说实话,我一直没用什么好思路,虽然网上有童鞋提供了一种思路是通过 setTheme 然后再 recreate Activity 的方式,但是这样带来的问题是非常多的,看起来就相当不科学(为什么不科学,后文会说)。于是,直接想到了去逆向分析那些夜间模式做得好的应用的源代码,学习他们的实现套路。所以,本文的实现思路来自于编写这些应用的夜间模式功能的童鞋,先在这里向他们表示感谢。我的手机里面使用高频的应用不少,其中简书和知乎是属于夜间模式做得相当 nice 的。先给两个效果图大家对比感受下

简书 知乎

如果大家仔细观察,肯定会发现,知乎的切换效果更漂亮些,因为它有一个渐变的效果。那么它们的夜间模式到底是如何实现的呢?别急接着往下看,你也可以。

实现套路

这里先展示一下我的实现效果吧

简书实现效果 知乎实现效果

此处分为两个部分,一部分是 xml 文件中要干的活,一部分是 Java 代码要实现的活,先说 xml 吧。

XML 配置

首先,先写一套UI界面出来,上方左边是两个 TextView,右边是两个 CheckBox,下方是一个 RecyclerView ,实现很简单,这里我不贴代码了。

接着,在 styles 文件中添加两个 Theme,一个是日间主题,一个是夜间主题。它们的属性都是一样的,唯一区别在于颜色效果不同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!--白天主题-->
<style name="DayTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
<item name="clockBackground">@android:color/white</item>
<item name="clockTextColor">@android:color/black</item>
</style>
<!--夜间主题-->
<style name="NightTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<item name="colorPrimary">@color/color3F3F3F</item>
<item name="colorPrimaryDark">@color/color3A3A3A</item>
<item name="colorAccent">@color/color868686</item>
<item name="clockBackground">@color/color3F3F3F</item>
<item name="clockTextColor">@color/color8A9599</item>
</style>

需要注意的是,上面的 clockTextColor 和 clockBackground 是我自定义的 color 类型属性

1
2
3
4
5
<?xml version="1.0" encoding="utf-8"?>
<resources>
<attr name="clockBackground" format="color" />
<attr name="clockTextColor" format="color" />
</resources>

然后再到所有需要实现夜间模式功能的 xml 布局文件中,加入类似下面设置,比如我在 RecyclerView 的 Item 布局文件中做了如下设置

稍稍解释下其作用,如 TextView 里的 android:textColor=”?attr/clockTextColor” 是让其字体颜色跟随所设置的 Theme。到这里,xml 需要做的配置全部完成,接下来是 Java 代码实现了。

继续阅读全文 »

RecyclerView 和 ListView 使用对比分析

本文主要记录 RecyclerView 和 ListView 的使用对比,文章主要包括以下几点的内容:

  • RecyclerView 和 ListView 布局效果的对比
  • RecyclerView 和 ListView 一些常用的功能 和 API 的对比
  • RecyclerView 和 ListView 在 Android L 引入嵌套滚动机制之后的对比

有一点需要强调下,文中所有的效果在真机上都是很流畅的,因为录制 GIF 图很容易掉帧,所以特地放慢了操作,千万不要误会成卡顿了啊!

布局效果对比

作为一枚控件,要引起开发者使用的欲望自然先是从显示效果看起(看脸的世界),ListView 大家对效果已经很熟悉了,这里直接跳过,而作为 RecyclerView,它能带给效果要比 ListView 强大得多,如下图

Android 默认提供的 RecyclerView 就能支持 线性布局网格布局瀑布流布局 三种(这里我们暂且不提代码细节,后文再说),而且同时还能够控制横向还是纵向滚动。怎样,从效果上足以碾压 ListView 有木有。

  • 横向滚动的ListView开源控件是不是可以不用再找了?对,你没看错!
  • 瀑布流效果的开源控件是不是可以不用再找了?对,你没看错!
  • 连横向滚动的GridView都不用找了!对,你没看错!

到此,展示效果上的差距一目了然。

API 使用对比

当然,一个控件我们不能完全只看效果,关键还是要看实用性,看看有没有方便我们调用的 API提高我们的开发效率。所以,接下来我们就从各个方面来看看 RecyclerView 和 ListView 在提供的API调用上的一些实践比较。

基础使用

ListView 的基础使用大家再熟悉不过,其使用的关键点主要如下:

  • 继承重写 BaseAdapter 类
  • 自定义 ViewHolder 和 convertView 一起完成复用优化工作

由于 ListView 已经老生常谈,所以此处就不去写示例代码了。 RecyclerView 基础使用关键点同样有两点:

  • 继承重写 RecyclerView.Adapter 和 RecyclerView.ViewHolder
  • 设置布局管理器,控制布局效果

示例代码大致如下:

继续阅读全文 »

深入理解 Android 中的 Matrix

在 Android 开发中,矩阵是一个功能强大并且应用广泛的神器,例如:用它来制作动画效果、改变图片大小、给图片加各类滤镜等。对于矩阵,Android 官方 SDK 为我们提供了一个强大的类 Matrix (还有 ColorMatrix )是一直困扰着我的问题,虽然大致能够调用相应的 API ,但却一直 get 不到其内在的梗。但是出来混总是别想着蒙混过关的,所以最近重新操起一年毕业的线性代数,再本着小事问老婆,大事问Google的心态,终于把多年不解的问题给破了。出于好记性不如烂笔头的原因,便有了本文。在此先感谢下面两篇令我茅舍顿开的文章:

读完本文,相信你能够搞明白以下三个问题:

  • 为什么 Matrix 是个 3 X 3 的矩阵
  • Matrix 这个 3 X 3 的矩阵每个元素的作用
  • Matrix 的 setXXX、preXXX、postXXX API 方法的工作原理

Matrix 的结构

Matrix 是 Android SDK 提供的一个矩阵类,它代表一个 3 X 3 的矩阵(不懂矩阵为何物的童鞋就要自行 Google 了)。 Matrix 提供了让我们获得 Matrix 值的 API —— getValues

利用此 API 传入一个长度为 9 的 float 数组,即可获得矩阵中每个元素的值。那么这 9 个浮点数的作用和意义是什么呢,从 Android 官方文档上看,它为这个数组中的每一个元素都定义了一个下标常量

这个 9 个常量取值分别是 0 - 8

如果我们将这个 float 排成直观的矩阵格式,那它将是下面这样子的

实际上我们平常利用 Matrix 来进行 Translate(平移)、Scale(缩放)、Rotate(旋转)的操作,就是在操作着这个矩阵中元素的数值来达到我们想要的效果。但是现在问题来了,上面提到的平移、缩放、旋转操作中,旋转和缩放可以用乘法表示,而平移就只能用加法表示,而且 Matrix 是一个 3 X 3 的矩阵,实际上表示这些操作 2 X 2 的矩阵足矣!

继续阅读全文 »