对于很多使用智能手机的用户来,很多抱怨手机耗电太快,很多人买手机的时候卖家都是推荐买两块电池,还有如果用户留心的话,在买手机的网页上,卖家会显示播放视频多长时间,听音乐多长时间,待机多长时间,不过看的最多的应该是他们说待机能够多长时间,今天写这篇文章是由于之前面试一家公司,老板问我如何说一个app算是一个好的程序,当时我给出了三点:1、界面UI 2、流畅度 3、处理耗时数据时,如何在UI上的体现。而后他说了两个耗电,网络,我对网络比较赞成,毕竟我们大多数app不是单机版的,时不时的都要去与网络交互,但是对于耗电我当时不太赞同,我当时的想法就是耗电是驱动模块应该考虑的,还有就是你不用就不耗电,你一直启动肯定要耗电,这个致使我走入一个误区,虽然当时不赞同,不过事后我想起来他们公司产品是要用到GPS的,不用说这个肯定很耗电,所以就查阅了一些资料,平常我们都是性能优化,很多人都会想起内存优化,UI优化等等,其实这些不仅不仅影响app的流程度也会增加电池的消耗的,只不过没有去关注罢了。既然发现了新大陆,所以我打算花上几天的时间去研究一下被我忽略的省电问题。

一、谁吃了我的电量

首先我们来看看Android手机的电量都主要消耗在了什么地方:

android背光设置 android背光调节原理 安卓屏幕背光调节_System

显而易见,大部分的电都消耗在了网络连接、GPS、传感器、CPU上了。

简单的说也就是主要在以下情况下耗电比较多:

1、 大数据量的传输。

2、 不停的在网络间切换。

3、 解析大量的文本数据。

上面的三点可以体现在很多方面比如网络图片显示方式,与后台交互数据时使用的传输方式,后台服务等等。那如何让电量飞的更长呢

二、用户角度来控制电量

2.1、屏幕亮度

我们所说的屏幕亮度也就是屏幕的背光,这就好比10瓦的电灯泡和50瓦的电灯泡,很多时候我们并不需要将屏幕亮度调到最高,实际上屏幕亮度是我们手机上那块硕大的屏幕最耗电的地方,所以适当的降低屏幕亮度将能很大程度上提高手机的待机能力,当然安卓系统提供了一个I自动调节亮度的功能,它能自动根据周围的环境来调节屏幕亮度,不过它依赖传感器的,而传感器我们在上面也提到也是耗电的罪魁祸首之一。

2.2、震动

在一些场合我们不希望来电或者信息的时候打扰周围的人,同样也不希望遗漏这些信息,我们通常会调成震动模式,如果不必要时候,不要开启震动,因为驱动手机的震动马达工作室需要消耗相当的电力的,所以如果不是在很有必要的情况下,最好关闭震动,听一下自己喜爱的铃声也是不错的选择。

2.3、按键音和触摸反馈

是不是触摸手机和按键的时候有一个叮当叮当的声音很爽呀,你是爽了,但是电量可就消耗掉了,只要操作手机有按键音和触摸反馈的时候就会消耗额外的电力,而且这也不是什么必须的东西,果断关掉。

2.4、GPS

GPS是一个好东西,出门在外特别是陌生的地方必不可少,记得我刚来上海的时候,带了折叠车上了地铁(我可是用东西包裹的,不然不让折叠车进),由于要转地铁,偏偏到转的地方最后一辆车走了,我只能拿着车子走出地铁站,由于人生地不熟的,还差到我住的地方还有一站有12里地吧,当时想拼车回去,但是司机算两个人,将半个人还不行,索性就打开百度地铁定位,在乌七八黑的路上乱窜,期间为了七八个人,成功与23点40分到家,GPS是个好东西,但是它确实耗电,幸好我带了移动电源不然只能睡在大街上了。在日常生活中的大多数时候我们都用不上GPS,但这并不意味着它没有在工作,所以出门的时候查完地图就关掉它吧。

2.5、蓝牙

近距离传输的好东西,不过只要你开着蓝牙,它就会一直吃掉你那可怜的电量,据说有些病毒也会通过蓝牙传播,所以果断关闭(当然,需要使用蓝牙的时候除外)。

2.6、自动同步

这个功能我是果断的关闭,它不仅耗电也耗流量,所以有需要的时候在开启,不用最好不要开启。

2.7、飞行模式

很多用户在晚上讨厌被骚扰,那么请果断打开飞行模式吧,关闭一切网络连接的手机将会惊人的省电,当然如果是小情侣的话,最好还是不要开启,不然某一个晚上的某一个时刻没有联系到你,第二天可能被轰击的,呵呵,所以要灵活使用飞行模式。

2.8、尽量使用官方ROM或者没有对CPU超频的ROM

对于超频这个词语应该很多人都听说过,超频会稍微提高手机的运行速度,也会大幅增强耗电,并让你的手机变得不那么稳定,实在有点得不偿失。

2.9、减少开关机次数

手机在开机的时候会重新搜索网络信号,重新加载所有的软件,而这都会消耗掉额外的电量。

2.10、不要在信号弱的地方通话

信号越弱,手机就会将天线的功率增加到越强,这不仅会增加手机的辐射,也会快速的消耗掉你的电池

2.11、不要使用自动任务管理器软件或者内存优化软件

很多用户感觉手机内存消耗比较大的时候,喜欢用内存优化软件杀死进程来释放内存,但是你有没有看的杀死的进程在后台又悄悄的开启了,对于Android手机来说很多在后台运行的软件并不会大量增加耗电量,如果使用任务管理软件把这些后台的软件杀光后反而会造成过多的重新载入时间,既浪费时间,又增加CPU的负担,当然也就增加了电池的消耗

2.12、关闭那些活跃在后台的程序

这一条并没有跟上面冲突,“活跃”的意思是指那些即便在后台,也会不断调用你的网络连接或者监视系统内存的软件,前者如QQ这样的即时通讯软件,后者就是在第2.11条中说过的自动任务管理软件

2.13、少装点桌面软件

安卓手机最大的优点之一就是桌面可以随意定制,例如ADW,Launcher Pro。不过对于使用HTC Sense、MIUI等这种深度定制系统的用户来说,即便你使用了这一类桌面软件,经过定制的桌面也会依然在后台运行,这无疑会增加我们手机的负担,降低速度并增加电量消耗,所以最好只选择一款自己习惯的软件。

2.14、不要使用动态桌面

动态桌面的确很炫,不过一直运行着一个那么炫的东西,当然要大量的电量支持

2.15、最好不要勾选程序的推送功能

实现推送功能说明程序一直在后台运行,要么客户端自己轮询查看服务器,要么服务器定时发送客户端数据,客户端来检测是否是新的信息,这不仅是耗电,而且也耗流量

2.16、不要常开WIFI

WIFI是好,不用消耗手机卡流量,但是它传输数据耗电

android背光设置 android背光调节原理 安卓屏幕背光调节_android_02

2.17、看视频,听音乐,玩游戏

当然这三样是用户主动的娱乐行为,不过它们确实耗电,音视频这东西要看到画面,不仅要在底层编解码还要渲染到手机上,所以最好找一款比较好的软件。

三、开发角度省电量

其实从用户角度省电量,同样也能反射到我们的app里面,当然这并不是简单的叠加的就行的。比如GPS,有些软件确实需要GPS来实现定位功能,当然我们也可以使用流量来定位,不过不如GPS准确,程序开启GPS后,如何去动态管理GPS,而不是仅仅用完了就放在这就行的。之前我在一家公司里面,涉及一个功能需要修改手机音量,我觉得最起码要有一个现场保护的功能,原来什么样那你就应该退出程序或者后台(不用这个功能的时候)还原回去,居然还遭到测试人员和其他平台开发人员的轰击,当时我就很纳闷,因为当时由于保护现场方法造成了一个bug,他们说这个做法是多余的,我之后默默改为这个bug也没有说什么了,我们做开发不仅仅是开发人员,同样也应该是一个资深的用户,说起规范,我看到测试人员给的bug,如果不是硬性问题,我首先会炮轰一遍,因为有些bug是测试人员的个人感觉,而他们给出的理由就是他们是测试人员是从用户的角度来看的,因为之前我也是做过测试的,所以只要遇到这样的问题,我也不会去争吵谁是用户,而是搜了一大堆同类功能的app,让他们对比,有时候争吵可能就是灵感的来源。

-----时间不早了,明天晚上继续讨论一下作为开发人员如何让我们app省电量 2014/1/7 0:39

接下来看看作为一个开发人员如何在我们的程序里面节省电量。

3.1、屏幕亮度

对于屏幕亮度的使用基本上可以分为两类,一类是调节手机背光的亮度比如用手机看电视,或者看小说的时候,很多程序会提供一个滑杆或者通过手势来让用户可以进行调节屏幕的亮度;另一类就是防止CPU进入休眠状态时,应用程序无法使用手机的一些功能,比如网络。

3.1.1、亮度调节

package com.jwzhangjie.smarttv_client.utils;

import android.app.Activity;
import android.provider.Settings;
import android.view.Window;
import android.view.WindowManager;

public class Functions {
	
	private Activity context;
	public Functions(Activity context){
		this.context = context;
	}
	/**
	 * 获得当前屏幕亮度的模式    
	 * SCREEN_BRIGHTNESS_MODE_AUTOMATIC=1 为自动调节屏幕亮度
	 * SCREEN_BRIGHTNESS_MODE_MANUAL=0  为手动调节屏幕亮度
	 */
	  public int getScreenMode(){
	    int screenMode=0;
	    try{
	    	screenMode = Settings.System.getInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE);
	    }
	    catch (Exception localException){
	    	
	    }
	    return screenMode;
	  }
	  
	 /**
	 * 获得当前屏幕亮度值  0--255
	 */
	  public int getScreenBrightness(){
	    int screenBrightness=255;
	    try{
	    	screenBrightness = Settings.System.getInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
	    }
	    catch (Exception localException){
	      localException.printStackTrace();
	    }
	    return screenBrightness;
	  }
	/**
	 * 设置当前屏幕亮度的模式    
	 * SCREEN_BRIGHTNESS_MODE_AUTOMATIC=1 为自动调节屏幕亮度
	 * SCREEN_BRIGHTNESS_MODE_MANUAL=0  为手动调节屏幕亮度
	 */
	  public void setScreenMode(int paramInt){
	    try{
	      Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE, paramInt);
	    }catch (Exception localException){
	      localException.printStackTrace();
	    }
	  }
	  /**
	   * 设置当前屏幕亮度值  0--255
	   * 需要权限android.permission.WRITE_SETTINGS
	   */
	  public void saveScreenBrightness(int paramInt){
	    try{
	      Settings.System.putInt(context.getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, paramInt);
	    }
	    catch (Exception localException){
	      localException.printStackTrace();
	    }
	  }
	  /**
	   * 保存当前的屏幕亮度值,并使之生效
	   */
	  public void setScreenBrightness(int paramInt){
	    Window localWindow = context.getWindow();
	    WindowManager.LayoutParams localLayoutParams = localWindow.getAttributes();
	    float f = paramInt / 255.0F;
	    localLayoutParams.screenBrightness = f;
	    localWindow.setAttributes(localLayoutParams);
	  }
	  
	
}

上面的代码可以实现调节亮度值和亮度模式,需要注意的是之前说过的保存现场,可以使用下面几种方式来保存:

1、Shared Preferences:主要用于保存程序的系统配置信息。用来存储“key-values paires”。一般用于保存程序启动时设定的信息,以便在程序下一次启动时继续保留前一次设定的信息。  2、Files:用文件的形式保存信息。可以通过对文件的读写来获取或保存相关信息。  3、SQLite:用数据库的形式保存信息。SQLite是一个开源的数据库 系统。  4、NetWork:将数据保存于网络。  5、ContentProvider:用于实现不同应用程序之间的数据共享。

一般这种行为仅限在Activity中,所以我们可以在onResume和onPause来实现亮度设置和还原。

3.1.2、CPU休眠

当我们把屏幕关闭,我们的Android手机会做出如何的表现呢,大多数会说CPU会进入睡眠或者长时间会进入深度睡眠状态,首先Android并不是真正的系统,只是基于Linux核心,本身并不具有类似windows和linxu操作系统的睡眠,也就不存在"深度睡眠"这种说法,再根据Aandroid平台架构体系,如果linux核心进入睡眠,那么Android这个平台的一切功能就将丧失。所以长时间手机处于关屏幕状态,在不同的阶段,驱动中的电源管理模块会采取不同的方式,来降低功耗,比如说一些不常用的硬件设备会断电,比如网络、摄像头、蓝牙、GPS等等,或者说这些相应的服务会关闭,手机并未进入"睡眠"状态,顶多进入休眠。就如上面所说的,有些服务会被关闭,而我们应用程序有时候不希望在手机进入休眠的时候,失去这些功能,就会获取系统权限,不让系统剥夺程序的使用权力,特别是网络,特别是那些具有推送功能的服务。那怎么来实现呢。

PowerManager 和 WakeLock这是Android提供给应用层来对cpu、屏幕、键盘灯控制。对它们进行加锁。实现方式如下:

/**
	  * 1、获取PowerManager实例
	  * 2、生成WakeLock实例,根据不同flag,获取指定的WakeLock,
	  * 不同的Lock对Cpu、屏幕、键盘灯有不同影响。
	  * 3、获取WakeLock实例后通过acquire()获取相应的锁,然后进行其他业务逻辑的操作,
	  * 最后使用release()释放(释放是必须的)
	  * @param flag
	  * <uses-permission android:name="android.permission.WAKE_LOCK"/>
	  * 你可能还需要
	  * <uses-permission android:name="android.permission.DEVICE_POWER"/>
	  */
	  public void acquireWakeLock(int flag) {
		  if (wakeLock ==null) {
			  PowerManager pm = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
			  wakeLock = pm.newWakeLock(flag, this.getClass().getCanonicalName());
			  wakeLock.acquire();
		  }
	  }
	  /**
	   * 释放锁
	   */
	  public void releaseWakeLock() {
		  if (wakeLock !=null && wakeLock.isHeld()) {
			  wakeLock.release();
			  wakeLock =null;
		  }
	 }

关于Flag的定义:

PowerManager.PARTIAL_WAKE_LOCK:保持CPU运行,屏幕和键盘灯有可能是关闭的

PowerManager.SCREEN_DIM_WAKE_LOCK:保持CPU运行,允许保持屏幕显示,但有可能是灰的,允许关闭键盘灯

PowerManager.SCREEN_BRIGHT_WAKE_LOCK:保持CPU运行,运行保持屏幕高亮显示,允许关闭键盘灯

PowerManager.FULL_WAKE_LOCK:保持CPU运行,保持屏幕高亮显示,键盘灯也保持亮度

PowerManager.ACQUIRE_CAUSES_WAKEUP:正常的唤醒锁没有打开亮度。相反,他们使亮度保持一旦打开(例如从用户的活动)。这个标志会使屏幕和/或键盘立即打开,当这个wakelock已获得。一个典型的使用将是,立即让用户看到的重要通知,比如推送功能。

PowerManager.ON_AFTER_RELEASE:这个标志被设置,用户活动定时器将被重置时wakelock已释放,使亮度保持长一点。这可用于如果你唤醒锁条件之间的循环减少闪烁。

WakeLock的设置是Activity级别的,不是针对整个Applicaiton的,所以在onResume方法里面操作WakeLock,在OnPause里面释放WakeLock

所以我们应该避免不合理的使用屏幕唤醒WakeLock.

3.2、频繁的进行数据更新

    对于需要连网的应用来说特别对那些要求实时性比较高的程序,数据的实时性很重要,但这也并不代表让你无节操的频繁更新数据,特别是全部更新以及全部覆盖的方式更新数据,对于开发人员来说这样做省事,相对于局部更新来说,少了很多的判断,以及较为发杂功能的实现,就拿我之前做的一个项目来说,信用卡历史记录的显示,需要显示的要素按月排序,显示当前的消费总额,并且要绘制与最高消费的比例长度的形式,显示当月消费并且画出它的长度,再一个就是具体的消费明细,其实这体现了一个头和内容,实现的效果要使用ExpandableListView,最简单的一种方法就是把所有的数据一次性从服务器拉下了,然后填充Group和Child,还有一种就是只获取头部数据,然后用户点击某个月,再从服务器获取当月的消费明细,如果用第一种方式实现直接解析数据,然后填充Group和Child,不必重写ExpandableListView,而第二种方式你就必须重写ExpandableListView来实现人为的判断是否需要从服务器获取数据,还是内存中已经有了这部分数据,直接展开子Child来显示。

    举一个简单的例子,ListView显示类似数据基本上最长用的,大多数需要自己重写BaseAdapter来实现自定义Item,问题在于刷新数据的时候,如何更新数据,对于刚开始的开发者会重新new adapter,在adapter的构造方法里面把新的数据传递进去,这种方式在初始化的时候用可以,但是比如在下拉更新的时候也使用这种方法就不好了,推荐还是把更新数据的部分提出来放在一个方法里面,毕竟BaseAdapter里面提供了notifyDataSetChanged, 比如:

public void updateListDatas(List<LiveVideoModel> listDatas){
	this.listDatas = listDatas;
	notifyDataSetChanged();
}

3.3、频繁GC

程序为什么会频繁GC呢。

3.3.1 GC原理

     Java语言是有垃圾回收机制,用以跟踪正在使用的对象和发现并回收不再使用(引用)的对象。该机制可以有效防范动态内存分配中可能发生的两个危险:因为内存垃圾过多而引发的内存消耗,以及不恰当的内存释放所造成的内存非法引用。

     垃圾收集算法的核心思想是:对虚拟机可用内存空间,即堆空间中的兑现进行识别,如果对象正在被引用,那么称其存活对象,反之,如果对象不再被引用,则为垃圾对象,可以回收其占据的空间,用于再分配。垃圾收集算法的选择和垃圾收集系统参数合理调节直接影响系统性能。

3.3.2、触发GC的条件

-----时间不早了,明天晚上继续讨论一下java的GC以及android中GC问题 2014/1/8 0:21

JVM进行次GC的频率很高,但因为这种GC占用时间极短,所以对系统产生的影响不大。更值得关注的是主GC的触发条件,因为它对系统影响很明显。总的来说有两个条件会触发主GC:

①当应用程序空闲时,即没有应用线程在运行,GC会被调用。因为GC在优先级最低的线程中进行,所以当应用忙时,GC线程就不会调用,但以下条件除外。

②Java堆内存不足时,GC会被调用。当应用线程在运行,并在运行过程中创建新对象,若这时内存空间不足,JVM就会强制调用GC线程,以便回收内存用于新的分配。若GC一次之后仍不能满足内存分配的要求,JVM会再进行两次GC作进一步的尝试,若仍无法满足要求,则JVM将报"out of memory"的错误,Java应用将停止。

由于是否进行主GC由JVM根据系统环境决定,而系统环境在不断的变化当中,所以主GC的运行具有不确定性,无法预计它何时必然出现,但可以确定的是对一个长期运行的应用来说,其主GC是反复进行的。

3.3.3、减少GC开销的措施

  根据上述GC的机制,程序的运行会直接影响系统环境的变化,从而影响GC的触发。若不针对GC的特点进行设计和编码,就会出现内存驻留等一系列负面影响。为了避免这些影响,基本的原则就是尽可能减少垃圾和减少GC过程中的开销。具体措施包括以下几个方面:

  (1)不要显示调用System.gc()

此函数建议JVM进行主GC,虽然只是建议而非一定,但很多情况下它会触发主GC,从而增加主GC的频率,也即增加了间歇性停顿的次数。

   (2)尽量减少临时对象的使用

临时对象在跳出函数调用后,会成为垃圾,少用临时变量就相当于减少了垃圾的产生,从而延长了出现上述第二个触发条件出现的时间,减少了主GC的机会。

   (3)对象不用时最好显式置为Null

一般而言,为Null对象都会被作为垃圾处理,所以将不用的对象显示的设为Null,有利于GC收集器判定垃圾,从而提高了GC的效率。

    (4)尽量使用StringBuffer/StringBuilder,而不用String来累加字符串

由于String是固定长的字符串对象,累加String对象时,并非在一个String对象中扩增,而是重新创建新的String对象,如Str5=Str4+Str3+Str2+Str1,这条语句执行过程中会产生多了个垃圾对象,因为对次作"+"操作时必须创建新的String对象,但这些过渡对象对系统来说是没有实际意义的,只会增加更多的垃圾。避免这种情况可以改用StringBuffer/StringBuilder来累加字符串,因StringBuffer/StringBuilder是可变长的,它在原有的基础上进行扩增,不会产生中间对象。

    (5)能用基本类型如int,double而不用Integer,Double对象

基本类型变量占用的内存资源比相应对象占用的少得多,如果没有必要,最好使用基本变量。

    (6)尽量少用静态对象变量

静态变量属于全局变量,不会被GC回收,它们会一直占用内存。

    (7)分散对象创建或删除的时间

集中在短时间内大量创建新对象,特别是大对象,会导致突然需要大量内存,JVM在面临这种情况时,只能进行主GC,以回收内存或整合内存碎片,从而增加主GC的频率。集中删除对象,道理也是一样的。它使得突然出现大量的垃圾对象,空闲空间必然减少,从而大大增加了下一次创建新对象时强制主GC的机会。

   其实有时我们调用System.gc()并不一定保证垃圾回收一定执行,它的作用只是提醒虚拟机:程序员希望进行一次垃圾回收,而具体什么时候进行是取决于具体的虚拟机的,不同的虚拟机有不同的对策。

3.3.4、Android程序GC

虽然看起来GC的耗时很短,在PC上确实看不出来,但是在移动设备上特别实时性高的程序里,例如视频播放,一个视频播放一般分为首先底层解码库拿到视频文件,然后把分析视频文件,分析音视频帧,根据不同编码,进行解码,解码出来的数据进行转换给上层应用进行渲染显示,这个过程很容易创建大量的临时对象,申请,之前在一个项目里面当我接收过来的时候,程序一运行起来的时候,看看终端的log,那个log就像不要钱的一样刷屏,当时视频显示用的是mjpeg,分辨率640X480,图片显示挺流畅的,但是后来摄像头换成H264的,这个时候需要解码,yuv转rgb,最后显示,就看出效果来了屏幕一片花,所以迫不得已进行从头优化,GC频繁的原因在于数据接收部分,视频的接收是使用socket来实现的每次读取大量的数据,然后按照协议解析长度和内容,当时的读用的是read()这个不是阻塞式的,所以需要自己实现阻塞,不让其他线程也就不能用了,整个UI就会卡死,我看了读取的方法有30多行,之前的解析策略是1、一次读取大量数据,二、使用while循环读取完整的一帧数据,解码,三、如果数据有剩余则保留,sleep,优化:使用readFull替换read,如果你查看readFull函数,能知道内部实现阻塞,只有读取到指定长度的数据才会返回,往下走,优化后的策略:一、先读取head,把数据的长度解析出来二、更加解析出来的长度,使用readFull读取一帧的数据,然后解码这帧数据,我们不需要自己使用sleep实现阻塞。只需要10条代码,半天没有看见因为读数据而造成GC,因为当时GC消耗的时间为20-30ms,真伤不起。

3.4、布局优化

同样实现相同的布局,但是内部结构千变万化,如何设计好的布局,这就需要经验积累了。我们可以从下面几个方向来优化:

3.4.1、充分利用系统资源

关于这方面的内容可以看Android开发优化之——对界面UI的优化(1)

3.4.2、减少布局层次

很多新手在布局的时候喜欢使用LinearLayout,因为比较简单,当然我并非说LinearLayout不好,在屏幕适应性的时候,LinearLayout的weight属性很好用,如果在一个布局中使用很多LinearLayout意味着布局存在很多嵌套,这样在虚拟机加载程序的时候需要耗时多,建议多用RelativeLayout,RelativeLayout自带的属性足以替代多少LinearLayout嵌套布局。

3.4.3、使用<include />重用Layout

在一个项目中我们可能会需要用到相同的布局设计,如果都写在一个xml文件中,代码显得很冗余,并且可读性也很差,所以我们可以把相同布局的代码单独写成一个模块,然后用到的时候可以通过<include /> 标签来重用layout代码。

3.4.4、使用<merge />减少视图层次结构

Android UI学习 - FrameLayou和布局优化

3.4.5、合理使用自带组件,减少组合模式

就如组合图片+文字(例如左右),一般我们通常用一个LinearLayout设置方向为水平,里面添加Imageview+TextView,如果你这样做的话,会提示你用Textivew来实现,TextView有如android:drawableXXX属性,我们可以通过这个方法可以设置图片+文字

3.4.6、合理善用java代码替换Xml布局

官方推荐布局使用Xml,不建议使用java代码,因为不具有通用,易懂性,但是有时候我们java代码实现局部布局,可以很好的解决布局的适应性。在Android性能优化---布局优化         

----由于今天晚上还要搞一些其他东西,所以今天就写到这里,明天晚上将介绍上面的布局优化里面提到的6条 2014/1/8 23:33

3.5、onResume和onPause

学习android开发的第一件事就是弄清楚Activity的生命周期,明白每一个生命周期的作用,这里主要说一下onResume和onPause,这个周期之间是Activity显示在顶层,也可以说前台,这里面我们可以把调用硬件的服务开启和关闭,动画开始和结束放在这两个函数里面,这样activity进入后台,就关闭,减少消耗。

3.6、使用软引用

我们可能要显示网络上面的图片,这样我们就需要去下载,显示,我们可以看一下网络开源的imageloader这个开源库,显示的步骤是先判断本地是否有,如果有加载到内存,然后用软引用关联,放在一个list里面,显示,如果不存在则下载到本地,好处就是能够把图片资源放在内存一段时间,当用的时候直接使用,内存不足时可以释放,增加 内存。

android背光设置 android背光调节原理 安卓屏幕背光调节_屏幕亮度_03

3.7、按需操控广播接收者

ComponentName receiver = new ComponentName(context, myReceiver.class); 
PackageManager pm = context.getPackageManager(); 
pm.setComponentEnabledSetting(receiver, 
PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP)

3.8、尽量使用application context

在android中有两种context,一种是 application context,一种是activity context。
public class BatteryActivity extends Activity { 
 	private static Drawable mBackground; 
 	protected void onCreate(Bundle state) { 
 		super.onCreate(state); 
 		TextView label = new TextView(this.getApplicationContext()); 
 		label.setText("It is good !"); 
 		if (mBackground == null) { 
			mBackground = getDrawable(R.drawable.battery_info); 
 		} 
	 	label.setBackgroundDrawable(mBackground);//drawable attached to a view 
 		setContentView(label); 
 	} 
}

3.9、数据库使用事务

SQLiteDatabase db = mHelper.getWritableDatabase(); 
db.beginTransaction(); 
try{
 	for (int i = 0; i < usageHisList.size(); i++) { 
	db.insert(table,null, values); 
}
	db.setTransactionSuccessful(); 
}catch(Exception ex){
}
db.endTransaction();

3.10、调整定时更新的频率

int alarmType = AlarmManager.ELAPSED_REALTIME; 
 long interval = AlarmManager.INTERVAL_HOUR; 
 long start = System.currentTimeMillis() + interval; 
 alarmManager.setInexactRepeating(alarmType, start,interval, pi);
 如果可以,请设置提醒的类型为ELAPSED_REALTIME or RTC而不是_WAKEUP。这样在系统睡眠的时候不会唤醒CPU。3.11、回收java对象
有些对象的回收不能依赖于JAVA的GC
 XmlPullParserFactory and BitmapFactory 
 Matcher.reset(newString) for regex 
 StringBuilder.setLength(0)

3.12、判断GPS开关状态

3.13、尽量使用GZIP进行文本数据传输

android背光设置 android背光调节原理 安卓屏幕背光调节_android_04

3.14、设置网络连接超时时间

android背光设置 android背光调节原理 安卓屏幕背光调节_android_05

3.15、网络

// 只在WiFi或3G下使用网络
NetworkInfo info;
int netType = info.getType();
int netSubtype = info.getSubtype();
if (netType == ConnectivityManager.TYPE_WIFI) {
	return info.isConnected();
 } else if (netType == ConnectivityManager.TYPE_MOBILE&& netSubtype == TelephonyManager.NETWORK_TYPE_UMTS && !mTelephony.isNetworkRoaming()) {
	return info.isConnected();
 } else {
	return false;
}