六木Sir
六木Sir
# 避免过度绘制 过度绘制(Overdraw)是在在屏幕上的某个像素在同一帧的时间内被绘制来多次。在多层次重叠的UI结构(如带背景的TextView)中,如果不可见的UI也在做绘制的操作,就会导致某些像素区被绘制来多次。 ## 导致过度绘制的原因 - XML布局 --- 控件有重叠且都有设置背景 - View自绘 --- View.onDraw里面同一个区域被绘制多次 ## 过度绘制检测工具Show GPU OverDraw - 无色: 没有过度绘制,每个像素绘制来1次 - 蓝色:每个像素多绘制来1次, - 绿色:每个像素多绘制来2次 - 淡红:3次,这个区域不超过屏幕的1/4是可以接受的 - 深红:4次及以上,需要优化
# 如何避免过度绘制之布局上的优化 - 移除XML中非必需的背景,或根据条件设置 - 移除Window默认的背景 - 按需显示占位背景图片 使用Android自带的一些主题时,activity往往会被设置一个默认的背景,这个背景由DecorView持有,当自定义布局有一个全屏的背景时,比如设置来这个界面的全屏黑色背景,DecorView的背景此时对我们来说是无用的,但是它会产生一次OverDraw,因此没有必要的话,也可以移除。 ``` protected void onCreate(Bundle savedInstancestate) { super.onCreate(savedInstanceState) this.getWindow().setBackgroundDrawable(null); } ``` 针对ListView中的Avatar ImageView的设置,在getView的代码中,判断是否获取对应的Bitmap,获取Avatar的图像之后,把ImageView的Background设置为Transparent,只有当图像没有获取到时,才设置对应的Background占位图片。
# 自定义View过度绘制优化 Canvas.ClipRect
# 启动优化之应用启动流程 Android 应用程序的载体是APK文件,其中包括来组件和资源,APK文件可能运行在一个独立的进程中,也有可能产生多个进程,还可以多个APK运行在同一个进程中,可以通过不同的方式来实现。 但需要注意两点: - 第一:每个应用只对应一个Application对象,并且启动应用一定会产生一个Application对象; - 第二:应用程序可视化组件Activity是应用的基本组成之一; ## Application Application 是Android系统框架中的一个系统组件,Android程序启动时,系统会创建一个Application对象,用来存储系统的一些信息。Android系统会自动在每个程序运行时创建一个Application类的对象,并且只创建一个,可以理解为Application是一个单例类。 应用可以不指定一个具体的Application,系统会自动创建,但一般在开发中都会创建一个继承于系统Applicaton的类实现一些功能,比如一些数据库的创建,模块的初始化等。但这个派生类必须在AndroidManifest.xml中定义好,在application标签增加name属性,并添加自己的Application的类名。 启动Application时,系统会创建一个PID,即进程ID,所有的Activity都会在此进程上运行。在Application创建初始化全局变量,同一个应用的所有Activity都可以读取到这些全局变量的值,Application的生命周期是整个应用程序中最长的,它的生命周期等于这个应用程序的生命周期,因为它是全局的单例的,所以在不同的Activity或者Service中获得的对象都是同一个对象。因此在安卓中要避免使用静态变量来存储长久保存的值,可以用Application,但并不建议使用太多的全局变量。 ``` public class LibApplication extends Application { @Override protected void attachBaseContext(Context base) { super.attachBaseContext(base); }...
# 启动优化之启动耗时检测 1.adb shell am  - ThsTime:一般和TotalTime时间一样,如果在应用启动时开了一个过度的全通明的页面(Activity)预先处理一些事,再显示出主页面(Activity),这样将比TotalTime小。 - TotalTime:应用的启动时间,包括创建进程+Applicaton初始化+Activity初始化到界面显示。 - WaitTime:一般比TotalTime大些,包括系统影响的耗时。 2.代码打点 ``` package com.errarehest.android.androidlib.utils.timemonitor; import android.util.Log; import java.util.HashMap; import java.util.Iterator; /** * Created by luohao on 2017/11/7. *...
# 合理的刷新机制 ## 减少刷新次数 - 控制刷新频率 - 避免没有必要的刷新 首先需要判断是否需要刷新,比如数据没有变化,需要刷新的控件(View)不在可见区域,就没有必要刷新。如果一个View从不可见到可见,一定要刷新一次。 ## 避免后台线程影响 在列表滚动的时候停止图片加载, example:ImageLoader加载图片 ## 缩小刷新区域 在以下两个场景下可以采用局部刷新的方法来节省更多的资源: - 自定义VIew中: 自定义View一般采用invalidata方法刷新。如果需要更新的数据只是在某一个区域内改变,在调用invalidata方法更新这个区域的时,也会更新整个视图,这就浪费了不需要更新的区域资源。Android系统提供了两个局部更新数据的方法: - invalidate(Rect dirty); - invalidate(int left, int top, int right, int...
# Android tools 一开始不明白,后来删掉这个属性之后发现会出现一个提示: pick preview layout from the "Fragment Layout" context menu 原来tools:layout仅仅是告诉编辑器,Fragment在程序预览的时候该显示成什么样,并不会对apk产生实际作用,是为开发者设计的。 一般来说被xmlns:tools="http://schemas.android.com/tools" 声明的tools作为前缀的属性都不会被编译进去。这个跟上面代码中tools:context是一样的。
# 内存优化之Android内存管理机制 ## Java对象的生命周期 - 创建阶段(Created) 为对象分配存储空间 开始构造对象 从父类到子类对static成员进行初始化 父类成员变量按照顺序初始化,递归调用父类的构造方法 子类成员变量按照顺序初始化,子类构造方法调用 一旦对象被创建,并有某个引用指向它,这个对象的状态就切换到了应用阶段(In Use) - 应用阶段(In Use) 对象至少被一个强引用持有并且对象在作用域内 - 不可见阶段(Invisible) 程序本身不再持有该对象的任何强引用,但是这些引用可能还存在着; 一般具体是指程序的执行已经超过该对象的作用域了 - 不可达阶段(Unreachable) 该对象不再被任何强引用所持有; 可能仍被JVM等系统下的某些已经装载的惊天变灵或者线程或JNI所持有,这些特殊的强引用被称为GC root,这种情况容易导致内存泄露,无法被回收 - 收集阶段(Collected) 对象不可达,并且GC已经准备好对该对象占用的内存空间重新分配的时候,处于手机阶段。 如果重写了finazlie()方法,则会去执行该方法。...
# 内存分配工具 ## Memory Monitor ## Heap Viewer ## Allocation Tracker
# 常见内存泄漏场景 ### 资源性对象未关闭 资源性对象(比如Cursor,File文件等)往往都使用类一些缓冲,在不使用的时候,应该及时关闭它们,以便它们的缓存数据能够及时回收。它们的缓存不只是存在于Java虚拟机内,还存在于Java虚拟机外。如果仅仅是把它们引用设置为null,而不关闭它们,往往会造成内存泄漏。因为有些资源性对象,比如SQLite Curosr(在析构函数finalize()中,如果没有关闭它,它自己会调用close()关闭),如果我们没有关闭它,系统在回收它时也会关闭它,但是这样效率太低了。所以应该调用colse函数,将其关闭,然后设置为null。 ### 注册对象未反注册(比如广播等) ### 类的静态变量持有大数据对象 ### 非静态内部类的静态实例 ### Handler 临时性内存泄漏 Handler通过发送Message与主线程交互,Message发出之后存储在MessageQueue中,有些Message也不是马上就被处理到,在Message中存在一个target,它是Handler的一个引用,Message在Queue中存在的时间过长,就会导致Handler无法被回收。如果Handler非静态的,则会导致Activity或者Service不被回收。 - 1.改成静态 - 2.内部弱引用外部的 - 3.外部销毁时Handler调用removeCallbacksAndMessage(null) 注:AsyncTask内部也是Handler机制,所以要注意,但是这种一般都是临时的。 ### 容器中的对象没清理造成的内存泄漏 如果对象的集合是一个static的,情况就严重了。 ### WebView