Android性能优化:APK瘦身
前言
随着业务迭代,APK体积逐渐变大。项目中积累的无用资源,未压缩的图片资源等,都为apk带来了不必要的体积增加,而APK的大小会影响应用加载速度、使用的内存量以及消耗的电量。
了解APK结构在讨论如何缩减应用的大小之前,有必要了解下应用APK的结构。APK文件由一个Zip压缩文件组成,其中包含构成应用的所有文件,这些文件包括Java类文件、资源文件和包含已编译资源的文件。
APK包含以下目录:
META-INF/:包含CERT.SF和CERT.RSA签名文件,以及MANIFEST.MF清单文件。
assets/:包含应用的资源;应用可以使用AssetManager对象检索这些资源。
res/:包含未编译到resources.arsc中的资源(图片、音视频等)。
lib/:包含特定于处理器软件层的已编译代码。此目录包含每种平台类型的子目录,如armeabi、armeabi-v7a、arm64-v8a、x86、x86_64和mips。
APK还包含以下文件。在这些文件中,只有AndroidMainfest.xml是必须的。
resources.arsc:包含已编译的资源 ...
Android运行时权限
引言我们在应用开发中如果需要联网就需要在AndroidManifest.xml文件中添加网络访问权限。在我们新安装应用时,往往会弹出提示框问我们是否允许系统获取定位、读取联系人、读取短信等权限。那这些权限有什么用?区别是什么?为什么会有运行时权限这一说法……下面让小编来一一梳理并解答。
运行时权限
Android的权限机制并不是什么新鲜事物,从系统的第一个版本开始就已经存在了。但其实之前Android的权限机制在保护安全和隐私等方面起到的作用十分有限,尤其是一些大家离不开的常用软件,非常容易“店大欺客”。为此,Android开发团队在Android6.0系统中引入了运行时权限这个功能,从而更好地保护了用户的安全和隐私。
Android权限机制详解如下,监听开机广播需要开启广播接收的权限:
因为监听开机广播涉及了用户设备的安全,因此必须在AndroidManifest.xml文件中加入权限声明,否则我们的程序就会崩溃。
那么问题来了,加入了这句权限声明后,对于用户来说到底有什么影响呢?为什么这样就可以保护设备的安全了呢?
其实用户主要在两方面得到保护。一方面,如果用户在低于Andr ...
OOM与内存优化
内存管理基础App内存组成以及限制Android 给每个 App 分配一个 VM ,让App运行在 dalvik 上,这样即使 App 崩溃也不会影响到系统。系统给 VM 分配了一定的内存大小, App 可以申请使用的内存大小不能超过此硬性逻辑限制,就算物理内存富余,如果应用超出 VM 最大内存,就会出现内存溢出 crash。
由程序控制操作的内存空间在 heap 上,分 java heapsize 和 native heapsize
Java申请的内存在 vm heap 上,所以如果 java 申请的内存大小超过 VM 的逻辑内存限制,就会出现内存溢出的异常
native层内存申请不受其限制, native 层受 native process 对内存大小的限制
如何查看Android设备对App的内存限制
主要查看系统配置文件 build.prop ,我们可以通过 adb shell 在 命令行窗口查看
adb shell cat /system/build.prop
通过代码获取
ActivityManager activityManager = (ActivityM ...
JVM内存管理深度剖析
JVM与操作系统的关系
以HelloWord.java程序为例,简单介绍一下java程序的执行过程
HelloWord.java通过javac编译成字节码文件HelloWorld.class
通过类加载器ClassLoader将字节码文件加载到运行时数据区(这个会在后面介绍)
通过执行引擎执行并与操作系统交互
关于Java SE体系结构
JVM只是一个翻译工具
JRE提供了基础类库
JDK提供了工具
JVM运行时数据区
Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域
程序计数器
虚拟机栈
本地方法栈
Java堆
方法区(运行时常量池)
线程私有的:虚拟机栈、本地方法栈、程序计数器
线程共享的:堆、方法区
程序计数器和栈
程序计数器是JVM内存区域中 唯一不会OOM的内存区
局部变量表只能存储8大数据类型(
byte[1]、short[2]、int[4]、long[8]、float[4]、double[8]、char[2]、boolean[1])+引用
一个线程有多个方法
一个方法一个栈帧
操作数栈:存放方法的执行 ...
自定义PhotoView手势处理
前言
前面介绍了前面介绍了嵌套滑动、自定义Behavior等高级UI实现原理,今天介绍一种比较简单的高级UI用法——手势处理。
你可以点开自己的手机相册,点开任意一张图片,双击图片会有放大效果,再次双击会缩小为原来大小。并且双指操作可以放大缩小图片。今天,小编就来实现一下这样的PhotoView效果。但是我的效果处理肯定不是很完美,毕竟追求代码简洁。
效果展示图:
手势处理API首先,先介绍一个Android处理单指手势的API GestureDetector,在创建一个GestureDetector对象时需要传入一个监听者OnGestureListener,所以我们需要实现OnGestureListener,通常实现SimpleOnGestureListener这个接口里面的功能就足够我们使用了,所以实现它即可。
SimpleOnGestureListener的方法介绍
class PhotoScaleGestureDetector extends GestureDetector.SimpleOnGestureListener{ //在ACTION_D ...
CoordinatorLayout原理解析与Behavior
CoordinatorLayout的功能事先警示:CoordinatorLayout只继承了NestedScrollParent,也就是说它只能做顶层父View,别踩坑!!!
处理子控件之间依赖下的交互
处理子控件之间的嵌套滑动
处理子控件的测量与布局
处理子控件的事件拦截与响应
以上四个功能,都建立与CoordinatorLayout中提供的一个叫做Behavior的“插件”之上。Behavior内部也提供了相应方法来对应这四个不同的功能。Behavior内部集成了上述四种功能对应的方法,实现解耦。
什么是Behavior?可以把Behavior理解成插件,当我们的组件想实现什么样的功能的时候就使用对应的Behavior,也就是说很多种不同功能的Behavior,当然也可以自定义Behavior。
CoordinatorLayout下依赖交互原理
当CoordinatorLayout中子控件dependency的位置、大小发生变化的时候,那么在CoordinatorLayout内部会通知所有依赖depandency的控件,并调用对应声明的Behavior,告知其依赖的 ...
NestedScrollView嵌套滑动原理
事件分发机制简介其实小编应该在前面准备一章关于Android的事件分发和处理机制的专题,因为时间原因和内容源码比较多吧(小编有强迫症,不想不贴源码),不过还是因为小编懒,哈哈。这里就对事件分发机制做一个简单的回忆,大家感兴趣的可以去看看相关资料和源码,小编后面有空也会出一期。
这里介绍一位优秀博主的博客,大家可以看这篇文章对事件分发机制与滑动冲突、以及解决方案有个全面的了解:
事件分发机制以及滑动冲突的处理
下面对事件分发与处理做一个简单总结
关键的一点大家需要记住:事件的分发是由上层到底层,而事件的处理是由底层到上层。
也就是说父View可以拦截触摸事件直接消费,而不传递给子View。
子View可以处理事件,也可以选择给父类消费。
ViewGroup既可以消费事件,也可以分发事件
View只能处理事件,也就是消费。
View滑动冲突
外部滑动方向与内部滑动方向不一致
解决方案:外部拦截法,当事件传递到父View时,父View需要处理此事件,就拦截,不处理此事件就不拦截
外部滑动方向与内部滑动方向一致;
内部拦截法,当事件传递到父View时,父View都传递给子Vi ...
深入理解并发编程和归纳总结
AQS什么是AQSAbstractQueueSynchronizer(抽象队列同步器)
是用来构建锁和其他同步组件的基础架构,比如ReentrantLock、ReetrantReadWriteLock和CountDownLatch就是基于AQS实现的。它使用一个int成员变量state标识同步状态,通过内置的FIFO(队列)来完成获取资源线程的排队工作。它是CLH队列锁的一种变体实现。它可以实现两种同步方式:独占式、共享式。AQS的主要使用方式是继承,子类通过继承AQS并实现它的抽象方式来管理同步状态,同步器的设计基于模板方法模式,所以如果要实现我们自己的同步工具类就需要其中几个可重写的方法,如tryAcquire、tryRelease、tryReleaseShared等等。这样设计的目的是同步组件(比如锁)是面向使用者的,它定义了使用者和同步组件交互的接口(比如可以允许两个线程并访问),隐藏了实现细节;同步器面向的是锁的实现者,它简化了锁的实现方式,屏蔽了同步状态管理、线程的排队、等待与唤醒等底层操作。这样就很好地隔离了使用者和实现者锁需关注的领域。在内部,AQS维护一个共享资源s ...
阻塞队列与线程池机制
创建线程的方式
1.Thread
2.Runnable(实例化接口,重新run方法,放入Thread中执行)
为什么Callable方式不算?
首先,我们都知道创建线程都需要通过Thread,那么我们来看一下Thread的构造函数
可以看到,Thread构造函数中压根就没有Callable类型的参数
接着,我们再来看看Callable,Callable是继承自FutureTask
通过上面的源码截图,我们可以看出来Callable本质上还是Runnable的一种实现
CASCompare And Swap
提及CAS之前,我们先来提一下原子操作,原子操作就是一气呵成,中间不能被打断,学过操作系统的朋友应该和熟悉,没错,就类似于操作系统中的中断原语。
CAS原理利用了现代处理器都支持的CAS的指令,循环这个指令,直到成功为止。
会有两个重要的属性变量,旧值与新值(需要更改的值),每次进入前都会用旧值与内存中的变量值进行比较,如果相同,就会用新值替换内存中的变量值,否则将再次循环上述过程。
CAS的问题ABA问题什么是ABA问题呢?
就是旧值为A,被替换为新值B, ...
adb小结
adb常用命令
与应用交互主要是使用am命令,常用的如下
command
用途
start [options]
启动 指定的 Activity
startservice [options]
启动 指定的 Service
broadcast [options]
发送 指定的广播
force-stop
停止 相关的进程
参数很灵活,和写 Android 程序时代码里的 Intent 相对应。
用于决定intent对象的选项如下:
参数
含义
—-
:—-
-a
指定 action,比如 android.intent.action.VIEW
-c
指定 category,比如 android.intent.category.APP_CONTACTS
-n
指定完整 component 名,用于明确指定启动哪个 Activity,如 com.example.app/.ExampleActivity
里还能带数据,就像写代码时的 Bundle 一样:
参数
含义
–esn
null 值( ...