Android性能優化之電量優化


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);
}
}
}



注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2020 ITdaan.com