被问到啊哈哈哈,宛如一个智障的我为什么没有想到!
性能优化肯定会省电啊啊啊
其他的没说,这个怎么……
憋说了,来来来,整理一波
转载自享受技术带来的快乐
(一)性能优化
Android开发除了NDK之外,使用的都是Java语言,而Java语言是一种基于虚拟机JVM运行的语言,所以相比C/C++语言来说,效率是比较低的。Java需要占用大量内存来换取执行速度,而不定期的GC机制,直接导致Android界面的卡顿现象。
Java语言优化
1. 使用非阻塞I/O
版本较低的JDK不支持非阻塞I/O API。为了避免I/O阻塞,一些应用采用了创建大量线程的方法(在较好的情况下,会使用一个缓冲池)。这种技术可以在许多必须支持并发I/O流的应用中见到,如web服务器等。然而,创建Java线程需要相当可观的开销。Java在JDK 1.4及以后版本中提供了一套API来专门操作非阻塞I/O,我们可以再java.nio包及其子包中找到相关的类和接口。由于这套API是JDK新提供的I/O API,因此,也叫New I/O,这就是包名nio的由来。这套API由3个主要的部分组成:缓冲区(Buffers)、通道(Channels)和非阻塞I/O的核心类。
2. 慎用异常
异常对性能不利。抛出异常首先要创建一个新的对象。 Throwable 接口的构造函数调用名为 fillnStackTrace()的本地(Native)方法,fillnStackTrace() 方法检查堆栈,收集调用跟踪信息。只要有异常被抛出,VM就必须调整调用堆栈,因为在处理过程中创建了一个新的对象。异常只能用于错误处理,不应该用来控制程序流程。
3. 变量和修饰符
不要重复初始化变量。默认情况下,调用类的构造函数时,Java会把变量初始化成确定的值:所有的对象被设置成null,整数变量(byte、short、int、long)设置成0,float和double设置成0.0,逻辑值设置成false。所有尽量不要重复初始化变量。
尽量使用局部变量,调用方法时传递的参数以及在调用中创建的临时变量都保存在栈(stack)中,速度较快,并且随所在线程的死亡而自动销毁。其他变量,如静态变量、实例变量等,都在堆(heap)中创建,速度较慢,垃圾回收是的耗能会导致APP出现卡顿现象。
尽量指定类的final修饰符。带有final修饰符的类是不可派生的。另外,如果指定一个类为final,则该类所有的方法都是final。Java编译器会寻找机会内联(inline)所有的final方法。此举能够使性能平均提高50%。
私有内部类要访问外部类的field或方法时,其成员变量不要用private,因为在编译时会生成setter/getter影响性能。可以把外部类的field或者方法声明为包访问权限。
如果方法用不到成员变量,可以把方法申明为static,性能会提高到15%到20%。
4. 其他方面:
- 用位操作代替乘除法;
- 用StringBuilder代替拼接操作;
- 对算法进行复杂度的改进(必要的时候可以空间换时间);
- 合理利用浮点数,浮点数比整形慢两倍。
- 网络优化、异步线程、图片使用缓存等。
UI布局优化
1.布局层数尽量少,RelativeLayout来代替LinearLayout,因为RelativeLayout性能更优,且可以简单实现LinearLayout嵌套才能实现的布局。
2.采用<merge>标签优化合并布局层数:系统在编译XML布局文件时不会为<merge>生成任何节点,通过合并可以大大减少标签的生成。
3.采用<include>标签共享重用其他布局:并用android:id属性覆盖被引用布局文件中顶层节点的android:id属性值。
<!—引用mylayout.xml文件>
<include android:id=”@+id/layout1” layout=”@layout/mylayout”/>
- <viewstub> 标签:viewstub标签同include标签一样可以用来引入一个外部布局,不同的是,viewstub引入的布局默认不会扩张,即既不会占用显示也不会占用位置,从而在解析layout时节省cpu和内存。 <viewstub> 常用来引入那些默认不会显示,只在特殊情况下显示的布局,如进度布局、网络失败显示的刷新布局、信息出错出现的提示布局等。
5.通过Android SDK中tools目录下的 layoutopt 命令查看你的布局是否需要优化。
6.将Activity中的window的背景图设置为空。 .getWindow().setBackgroundDrawable(null) ;android默认的背景不为空。
7.View中设置缓存属性 lsetDrawingCache l为true。动态加载View时采用ViewStub避免一些不经常的视图长期握住引用。
8.采用SurfaceView在子线程刷新UI,避免手势的处理和绘制在同一UI线程(普通View都这样做)。
-
9.ListView的优化
- item尽可能的减少使用的控件和布局的层次;
- RelativeLayout是绝对的利器,通过它可以减少布局的层次。
- 尽可能的复用控件,这样可以减少 ListView的内存使用,减少滑动时GC次数。
- ListView的背景色与cacheColorHint设置相同颜色,可以提高滑动时的渲染性能。
- ListView中getView是性能是关键,这里要尽可能的优化。
- getView方法中要重用view;
- getView方法中不能做复杂的逻辑计算, 特别是数据库操作,否则会严重影响滑动时的性能。
数据库优化
有些能用文件操作的,尽量使用文件操作,文件操作的速度比数据库的操作要快10倍左右。
Cursor的使用,管理好cursor,不要每次打开关闭cursor,因为打开关闭cursor非常耗时。Cursor.require用于刷cursor。同时由于SQLiteDatabase对象较为耗费资源,所以我们在使用完SQLiteDatabase对象之后,必须立即关闭它,避免它继续占用资源,否则我们继续程序可能会导致OOM或者其他异常。
SQLite使用事务,也可以自定义事务。使用事务好处是原子提交和更优性能。
Db.beginTransaction();
Db.setTransactionSuccessful();
Db.end Transaction();
可以建立索引,增加检索的速度。(当某字段数据更新频率较低,查询频率较高,经常有范围查询(>,<, =, >=, <=)或orderby、group by发生时建议使用索引; 经常同时存取多列,且每列都含有重复值可考虑建立复合索引)。
批量插入、更新使用原子操作,采用事务等方式。
查询时返回更少的结果集及更少的字段。
少用cursor.getColumnIndex(可以在建表的时候用static变量记住某列的index,直接调用相应index而不是每次查询。)
优化sql语句字符串等,语句的拼接使用StringBuilder代替String。
新机制或者借用工具
- 采用JNI技术,将耗时间的处理放到c/c++层处理。适当的采用NDK编程可以提高效率,但是内存回收不稳定,所以说适当。
懒加载和缓存机制:访问网络的耗时操作启动一个新线程来做,而不要在UI线程做。还有从网络上获取大量图片的时候,可以本地缓存,下次获取同样图片的时候,可以先从本地获取,本地无再从网络获取。
通过Android SDK中tools目录下的layoutopt命令查看你的布局是否需要优化;hierarchy viewer可以方便的查看Activity的布局,各个View的属性、measure、layout、draw的时间,如果耗时较多会用红色标记,否则显示绿色;利用android自带的性能跟踪工具TraceView查看跟踪函数调用,跟踪方法跟踪各部分的执行效率。
可以在方法执行前后各使用system.currentTimeMillis方法获取当前系统的时间(毫秒),两个时间之差可以计算出方法的执行时间,进而可以改进优化。
获取系统的内存信息
//获取系统内存总数
Long total = Runtime.getRuntime().totalMemory();
//获取剩余内存
Long free = Runtime.getRuntime().freeMemory();
//获取已经使用内存
Long used = total – free;
(二)Android省电开发之CPU降频
转载自Matrixxu博客专栏
在Android系统的耗电量排行里,cpu的耗电占了比较大的一部分比例,也就是说,cpu的使用率和使用频率将直接或间接的影响电量的分配和使用,但很遗憾,android-sdk中没有为android的开发者提供类似cpu管理的功能,但是当下很多省电类应用或专业的cpu管理软件都提供了cpu的降频甚至是超频的功能,那么这样的功能是如何实现的,本文将详细说明在android环境下调整cpu频率的一些方法,仅供参考。
- CPU的工作频率
单位赫兹或者兆赫兹。CPU的工作频率越高,耗电量越大,反之亦然。
- CPU的调控模式
英文词为:Governor,解释为调速器,控制器。android的framework是基于Linux平台的,那么cpu的管理体系这块也跟linux基本上一样,其中包括cat命令,和一些文件的读写配置都是基本上差不多的。Linux在管理CPU方面,提供了如下几种调控模式,分别为:
调控模式 | 效果 |
---|---|
performance | 将CPU的工作频率调整到最大模式,让CPU充分工作 |
powersave | 将cpu的工作频率调整到节能模式,这个模式下的CPU频率最低 |
ondemand | 定期检查负载。当负荷超越了阈值,设置的CPU运行以最高的频率。当负载低于相同的阈值,设置的CPU运行在下一个的最低频率。导致更少的延迟比。ondemand从字面翻译是“根据需求,按照需要”,cpu在工作的时候频率会在一个最大值和最小值之间波动,当负载提高时,该调控期会自动提高cpu的频率,反之亦然。“Causes less latency than the conservative governor.”这句话的意思是,该模式跟conservative相比,会导致更少的延迟。ok,那让我们再看看conservative是如何解释的。 |
conservative | 该模式与ondemand的最大区别在于:conservative模式不会立刻在负载增加的情况下将cpu频率调整到最大,会调整到比目前频率稍微大的频段去工作。所以在某种极端情况下,该模式的延迟会大于ondemand。 |
usersapce | 将cpu的掌控权交给了用户态,也就是交给了应用程序,应用程序可以通过配置文件的方式修改cpu的频率信息。 |
public class CPUFreqSetting {
/**
* cpu cat命令大全
* cat [%cpuFreqPath%]/cpuinfo_cur_freq (当前cpu频率)
* cat [%cpuFreqPath%]/cpuinfo_max_freq (最大cpu频率)
* cat [%cpuFreqPath%]/cpuinfo_min_freq (最小cpu频率)
* cat [%cpuFreqPath%]/related_cpus (cpu数量标号,从0开始,如果是双核,结果为0,1)
* cat [%cpuFreqPath%]/scaling_available_frequencies (cpu所有可用频率)
* cat [%cpuFreqPath%]/scaling_available_governors (cpu所有可用调控模式)
* cat [%cpuFreqPath%]/scaling_available_governors (cpu所有可用调控模式)
* cat [%cpuFreqPath%]/scaling_cur_freq (?????)
* cat [%cpuFreqPath%]/scaling_driver (?????)
* cat [%cpuFreqPath%]/scaling_governor (?????)
* cat [%cpuFreqPath%]/scaling_max_freq (?????)
* cat [%cpuFreqPath%]/scaling_min_freq (?????)
* cat [%cpuFreqPath%]/scaling_setspeed (?????)
* cat [%cpuFreqPath%]/cpuinfo_transition_latency (?????)
*/
private final String TAG = "SetCPU";
private final String cpuFreqPath = "/sys/devices/system/cpu/cpu0/cpufreq";
private final static String PERFORMANCE_GOVERNOR = "performance";
private final static String POWER_SAVE_GOVERNOR = "performance";
private final static String ONDEMAND_GOVERNOR = "performance";
private final static String CONSERVATIVE_GOVERNOR = "performance";
private final static String USERSAPCE_GOVERNOR = "performance";
// public void powerSaveGovernor() {
// List<String> governors = readCpuGovernors();
// if (governors.contains(object)) {
//
// }
// }
/**
* 获得当前CPU调控模式
*/
public void getCpuCurGovernor() {
try {
DataInputStream is = null;
Process process = Runtime.getRuntime().exec("cat " + cpuFreqPath + "/scaling_governor");
is = new DataInputStream(process.getInputStream());
String line = is.readLine();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 重写CPU调控模式
* @param governor
* @return
*/
private boolean writeCpuGovernor(String governor) {
DataOutputStream os = null;
byte[] buffer = new byte[256];
String command = "echo " + governor + " > " + cpuFreqPath + "/scaling_governor";
Log.i(TAG, "command: " + command);
try {
Process process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(command + "\n");
os.writeBytes("exit\n");
os.flush();
process.waitFor();
Log.i(TAG, "exit value = " + process.exitValue());
} catch (IOException e) {
Log.i(TAG, "writeCpuGovernor: write CPU Governor(" + governor + ") failed!");
return false;
} catch (InterruptedException e) {
e.printStackTrace();
}
return true;
}
/**
* 获得CPU所有调控模式
* @return
*/
private List<String> readCpuGovernors() {
List<String> governors = new ArrayList<String>();
DataInputStream is = null;
try {
Process process = Runtime.getRuntime().exec("cat " + cpuFreqPath + "/scaling_available_governors");
is = new DataInputStream(process.getInputStream());
String line = is.readLine();
String[] strs = line.split(" ");
for (int i = 0; i < strs.length; i++)
governors.add(strs[i]);
} catch (IOException e) {
Log.i(TAG, "readCpuGovernors: read CPU Governors failed!");
}
return governors;
}
}
(三)Android省电开发之service
Android应用开发中,难免会遇到service开发。android中服务是运行在后台的东西,级别与activity差不多。既然说service是运行在后台的服务,那么它就是不可见的,没有界面的东西。Service和其他组件一样,都是运行在主线程中,因此不能用它来做耗时的请求或者动作。你可以在服务中开一个线程,在线程中做耗时动作。
** 我们从三个方面来浅析一下service的省电开发**
** 查看service是否存活以及降低优先级:**
假如一个service工作完成,但是来不及关掉或者kill掉,用户又看不见,所以这个service将会一直在后台运行,势必耗电。所以我们可以降低某些不常用service进程的优先级,在系统内存吃紧的情况下, 进程优先级低的service容易被系统kill掉。除此之外,可以利用监听系统广播来判断service状态是否存活,死亡即可手动kill掉。** 用IntentService代替Service开发:**
普通服务一旦启动之后,就会一直处于运行状态,必须调用stopService()或者stopSelf()方法才能让服务停止下来。为了简单的创建一个异步的、会自动挺值得服务,Android专门提供了一个IntentService类。IntentService在运行完毕后自动停止,减少耗电量。** 后台执行的定时任务Alarm机制:**
Service没必要一直在后台运行,这时候的定时任务显得很重要。
Android的定时任务有两种实现方式,Timer类和Alarm机制。
- Timer有一个明显的短板,不适合长期后台运行的定时任务。为了能让电池更加耐用,每种手机都会有自己的休眠策略,Android手机就会在长时间不操作的情况下自动让CPU进入到睡眠状态,这就有可能导致Timer中的定时任务无法正常运行。
- Alarm机制则不存在这种情况,它具有唤醒CPU的功能,即可以保证每次需要执行定时任务的时候CPU能正常工作。
♬ PS:Alarm机制
从Android 4.4之后,Alarm任务的触发时间将会变得不准确,有可能会延迟一段时间后任务才能得到执行。这不是bug,而是系统在耗电性方面进行的优化。系统会自动检测目前有多少Alarm任务存在,然后将触发时间将近的几个任务放在一起执行,这就可以大幅度的减少CPU被唤醒的次数,从而有效延长电池的使用时间。
但是,Android提供了解决方案,使用AlarmManager的 setExact() 来代替 set() 方法,基本可以保证任务准时执行。
public class MyService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
new Thread() {
@Override
public void run() {
//耗时操作
}
}.run();
AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
long triggerAtTime = SystemClock.elapsedRealtime() + 10 * 1000;
Intent intent = new Intent(this, MyService.class);
PendingIntent pendingIntent = PendingIntent.getService(this, 0, intent, 0);
manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pendingIntent);
return super.onStartCommand(intent, flags, startId);
}
}
// 让定时任务的触发时间从系统开机算起,不会唤醒CPU
AlarmManager.ELAPSED_REALTIME;
//让定时任务的触发时间从系统开机算起,会唤醒CPU
AlarmManager.ELAPSED_REALTIME_WAKEUP;
// 让定时任务的触发时间从1970年1月1日0点算起,不会唤醒CPU
AlarmManager.RTC;
// 让定时任务的触发时间从1970年1月1日0点算起,会唤醒CPU
AlarmManager.RTC_WAKEUP;
// 获取系统开机至今所经历时间的毫秒数
SystemClock.elapsedRealtime();
// 获取从1970年1月1日0点至今所经历时间的毫秒数
SystemClock.currentThreadTimeMillis();
(四)Android省电开发之网络
除了常规的异步网络、多线程技术、本地缓存等等之外,Android省电开发还有一个重要的方面是: WIFI 比蜂窝数据更省电:
- a)尽量在Wi-Fi下传输数据,当然这是废话,不过可以考虑在有Wi-Fi的时候做预加载,比如应用中心的zip包、手Q web类应用的离线资源等;
- b)非Wi-Fi下,尽量减少网络访问,每一次后台交互都要考虑是否必须。虽然WiFi接入方式已经占到移动互联网用户的50%,但是是有些手机设置为待机关闭WiFi连接,即便有Wi-Fi信号也只能切换到蜂窝数据;
一篇博文中的数据测试
灭屏情况:灭屏传输,高负载download的时候WiFi最省电(70mA),3G(270mA)和2G(280mA)相当,是WiFi的4倍左右;
亮屏情况:亮屏传输,高负载download的时候WiFi最省电(280mA),3G(360mA)和2G(370mA)相当,是WiFi的1.3倍左右;
所以在Android应用省电开发中,我们可以在获取网络方式的方面加以考虑。
(五)Android省电开发之Android L5.0(ART)登场
-
1. 默认的ART运行模式
安卓4.4系统中引入了全新的ART模式吗,相比之前流行已久的Dalvik模式有了很大的改变。
在Dalvik中,应用每次运行,字节码都需要通过即时编译器转换为机器码,这回拖慢应用的运行效率,而在ART环境中,应用在第一次安装时,字节码就会预先编译成机器码,使其成为了真正的本地应用。这个过程叫做预编译。这样的话,应用的启动和执行都会变得更加快速。但是ART的缺点是预编译完的机器人占用了更大的存储空间,应用的安装需要更长的时间。但是牺牲空间时间换取省电速度,在Android应用中还是可以接受的,毕竟性能的提升,运行速度的变快,体验更流畅,电池续航更久显得更重要。
- 2.利用JobScheduler API
过去,如果开发人员想通过后台调取服务器数据,或完成某些处理工作,应用程序必须先监听是否有事件正在发生,并为自己设定一个唤醒时间,一旦应用程序开始运行,他需要检查各种环境条件,以确定是否具备条件让它完成工作,还是需要稍后再试,这种方式不仅复杂,而且容易出错,它会不断的浪费资源,比如当 一个应用程序被唤醒后,发现条件不符合就只能去睡觉并为下次唤醒再次设定时间,这是一个反复的过程。
这个问题,将引用 JobScheduler 来修复,它作为一个调度应用程序,负责当应用程序被唤醒时,提供适当的运行环境,所以开发者不用再让程序检测环境是否符合需求,开发人员只需要按照标准的流程来,调度程序会自动为唤醒的程序,准备好运行环境。应用程序可以使用这个调度程序,来唤醒他们,比如当设备连接到充电器后,调度程序将唤醒那些需要处理器工作的程序,让他们进行工作,或者在设备连接至WiFi网络的时候上传下载照片,更新内容等。该调度程序还支持一个时间窗口,以便它可以唤醒一组应用程序,这将使那些不需要精确唤醒时间,但每隔一两小时需要运行一次的程序能在同一时间点运行,这样就能让处理器保持更长时间的休眠。
JobScheduler 的优势相当巨大,它不仅可以帮助手机节省电量, 实际由于不在需要监听,更改和设置报警,还可以帮助开发人员减少代码书写量。目前该JobScheduler类,已经加入Android L开发者预览版。
-
3.各种省电新模式和新技术
(1) 全新的Material Design风格用户界面
新的用户界面更加简洁、色彩更加丰富。动画效果更加合理生动,同时加入实时阴影的3D视图,更多的使用卡片风格的显示效果。全平台风格也变得更为统一。(2) 新的通知消息系统
允许用户管理通知中心中的通知消息。原先的Android通知栏几乎是处于无法控制的状态,所有的应用通知都会弹出,要想关闭只能进到每一个应用中去单独设置,或是使用第三方软件来实现统一管理。但是现在不用了,Android 5.0已经自带了通知管理界面。(3) 多任务界面有着全新的Google Now卡片风格
通知中心融入更多的卡片式风格,即使是在锁屏状态下也可以进行多种功能操作。同时用户可以自定义通知的优先级别,使得用户不会错过任何重要的通知。还可以设置特定的通知权限,只有被允许的通知消息才会推送。同时还具有操作性,比如用户在游戏时有电话打入,不会以全屏显示,而是弹出可操作的通知卡片,用户可选择接听或拒接,不影响游戏继续进行。(4) Project Volta省电模式、BatterySaver省电模式
Android 5.0的省电模式是通过 JobSchedulerAPI 以及自动调节屏幕亮度、刷新率来达到省电的效果,而且还使用了Project Volta量化每个应用的耗电量,在手机快没电的情况下主动降低CPU的主频或者关闭通讯模块,以获得更长的待机时间。还配备了一个 Battery Bistorian 电池历史记录功能,可让详细显示设备的耗电情况。
以上整理自网络~
如有错误还请大家多多指教啊哈哈