Android性能优化之电量优化

时间:2022-12-09 18:42:05
1、在android framework里面有专门负责电量统计的Service:BatteryStatsSerive
①这个Service在ActivityManagerService中创建,代码如下:
 
 
mBatteryStatsService = new BatteryStatsService(new File(systemDir, 'batterystats.bin').toString());
②其他的模块比如WakeLock和PowerManagerService会向BatteryStatsService传递数据,数据是存放到系统目录batterystats.bin文件,然后交于BatteryStatsImpl这个数据分析器来进行电量数据的分析,系统的设置就是这样得到电量的统计信息的;
③电量的计算公式:
 
 
应用运行总时间 = 应用在Linux内核态运行时间 + 应用在Linux用户态运行时间
CPU工作总时间 = 软件运行期间CPU每个频率下工作的时间之和比例
应用消耗的电量 = CPU每个频率等级下工作的时间比例/CPU工作总时间 * 应用运行总时间

2、手机耗电主要原因

在09年GoogleIO大会JeffreySharkey的演讲(Coding for Life — Battery Life,That Is)中就探讨了这个问题,指出android应用的耗电主要在以下三个方面:
大数据量的传输
不停的在网络间切换
解析大量的文本数据;

3、并提出了相关的★优化建议

①在需要网络连接的程序中,首先检查网络连接是否正常,如果没有网络连接,那么就不需要执行相应的程序;
②判断网络类型,针对特定的数据在特定的网络下请求.例如:大量数据传输的时候在wifi下请求;wifi下下载数据耗电量只有2、3、4G的1/3.
③使用效率高的数据格式和解析方法,推荐使用JSON和Protobuf;
④在进行大数据量下载时,尽量使用GZIP方式下载;
⑤使用推送,代替循环请求
⑥其它:
  • 尽量不要使用浮点运算
  • 回收java对象,特别是较大的java对像,使用reset方法;
  • 主动回收java对象,特别是较大的,例如bitmap。减少GC的工作频率;
  • 避免内存抖动,内存抖动是因为大量的对象被创建又在短时间内马上被释放;
  • 避免在for循环、onDraw方法中创建对象;无法避免的可以创建对象池,然后在不使用的时候释放;
  • 对定位要求不是太高的话尽量不要使用GPS定位,可以使用wifi和移动网络cell定位即可;
  • 获取屏幕尺寸等信息可以使用缓存技术,不需要进行多次请求;
  • 使用AlarmManager来定时启动服务替代使用sleep方式的定时任务;
4、限制APP对电量的影响:
①当没有网络连接的时候,禁用后台服务更新
②当电池电量低的时候减少更新的频率,确保自己的app对电池的影响降到最低
③检查是否在充电
 
  
<receiver android:name=".PowerConnectReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_POWER_CONNECTED"/>
<action android:name="android.intent.action.ACTION_POWER_DISCONNECTED"/>
</intent-filter>
</receiver>
 
  
public class PowerConnectionReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1);
boolean isCharging = status == BatteryManager.BATTERY_STATUS_CHARGING || status == BatteryManager . BATTERY_STATUS_FULL ;
int chargeFlag = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargeFlag == BATTERY_PLUGGED_USB;
boolean acCharge = chargeFlag == BATTERY_PLUGGED_AC;
}
}
 
   
//获取程序是否充电
int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,-1);
boolean isCharging = (status == BatteryManager.BATTERY_STATUS_CHARGING||status == BatteryManager.BATTERY_STATUS_FULL);
 
    
// 充电方式,usb还是电源
int chargeFlag = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1);
boolean usbCharge = chargeFlag == BATTERY_PLUGGED_USB;
boolean acCharge = chargeFlag == BATTERY_PLUGGED_AC;
④不断的检测电量也会影响电池的使用时间,我们可以这样做
 
    
<receiver android:name=".BatteryLevelReceiver">
<intent-filter>
<action android:name="android.intent.action.ACTION_BATTERY_LOW"/>// 电量过低
<action android:name="android.intent.action.ACTION_BATTERY_OKAY"/>
</intent-filter>
</receiver>

5、使用JobScheduler合理分配任务

①JobScheduler 即 任务调度器
②需要先有一个JobService
 
    
public class MyJobService extend sJobService {
private static final String LOG_TAG="MyJobService";
@Override
public void onCreate() {
super.onCreate();
Log.i(LOG_TAG,"MyJobServicecreated");
}
@Override
public void onDestroy() {
super.onDestroy();
Log.i(LOG_TAG,"MyJobServicedestroyed");
}
@Override
public boolean onStartJob(JobParameters params) {
Log.i(LOG_TAG,"Totallyandcompletelyworkingonjob"+params.getJobId());
if(isNetworkConnected()) {
new SimpleDownloadTask().execute(params);
return true;
} else {
Log.i(LOG_TAG,"Noconnectiononjob"+params.getJobId()+";sadface");
}
returnfalse;
}
@Override
public boolean onStopJob(JobParameters params) {
Log.i(LOG_TAG,"Whelp,somethingchanged,soI'mcallingitonjob"+params.getJobId());
return false;
}
private boolean isNetworkConnected() {
ConnectivityManager manager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = manager.getActiveNetworkInfo();
return(networkInfo!=null&&networkInfo.isConnected());
}
}
 
    
private class SimpleDownloadTask extends AsyncTask<JobParameters,Void,String> {
protected JobParameters mJobParam;
@Override
protected String doInBackground(JobParameters...params) {
mJobParam = params[0];
     InputStream is=null;
try {
int len=50
URL url=new URL("https://www.google.com");
HttpURLConnection conn=(HttpURLConnection)url.openConnection();
conn.setReadTimeout(10000);//10sec
conn.setConnectTimeout(15000);//15sec
conn.setRequestMethod("GET");
conn.connect();
int responseCode=conn.getResponseCode();
Log.d(LOG_TAG,"Theresponseis:"+responseCode);
is=conn.getInputStream();
Reader reader = new InputStreamReader(is,"UTF-8");
char[] buffer=new char[len];
reader.read(buffer);
return new String(buffer);
} catch(IOExceptione) {
return"Unabletoretrievewebpage.";
}
}
@Override
protected void onPostExecute(String result) {
jobFinished(mJobParam,false);
Log.i(LOG_TAG,result);
}
}
③然后模拟通过点击Button触发N个任务,交给JobService来处理:
 
     
public class FreeTheWakelockActivity extends ActionBarActivity {
public static final String LOG_TAG="FreeTheWakelockActivity";
TextView mWakeLockMsg;
ComponentName mServiceComponent;
@Override
protected void onCreate(BundlesavedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_wakelock);
mWakeLockMsg = (TextView)findViewById(R.id.wakelock_txt);
mServiceComponent = new ComponentName(this,MyJobService.class);
Intent startServiceIntent = new Intent(this,MyJobService.class);
startService(startServiceIntent);
Button btn = (Button)findViewById(R.id.wakelock_poll);
btn.setText(R.string.poll_server_button);
btn.setOnClickListener(new View.OnClickListener() {
@Override
publicvoidonClick(Viewv) {
pollServer();
}
});
}
public void pollServer() {
JobScheduler scheduler = (JobScheduler)getSystemService(Context.JOB_SCHEDULER_SERVICE);
for(int i=0; i<10; i++) {
JobInfo jobInfo=new JobInfo.Builder(i,mServiceComponent)
.setMinimumLatency(5000)//5seconds
.setOverrideDeadline(60000)//60seconds(for brevity in the sample)
.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)//WiFi or data connections
.build();
mWakeLockMsg.append("Schedulingjob"+i+"!n");
scheduler.schedule(jobInfo);
}
}
}