#android电池电量优化
在09年Google IO大会Jeffrey Sharkey指出android应用的耗电量主要在以下三个方面:

  • 大数据量的传输
  • 不停地在网络间切换
  • 解析大量的文本数据

并提出了相关的优化建议:

  • 在需要网络连接的程序中, 首先检查网络连接是否正常,如果没有网络连接,就不要执行相应的程序
  • 使用效率高的数据格式和解析方法,推荐使用JSON和Protobuf
  • 在进行大数据量下载时,尽量使用GZIP方式下载
  • 其他:回收java对象,特别是较大的java对象,使用reset方法;对定位要求不是太高的话尽量不要使用GPS定位;尽量不要使用浮点运算;获取屏幕尺寸等信息可以使用缓存技术,不需要进行多次请求;使用AlarmManager来定时启动服务替代使用sleep方式的定时任务

作为app开发者,应该限制app对电量的影响,当没有网络连接的时候,禁用后台服务更新,当电池电量低的时候减少更新的频率,当电池充电或者电量比较饱和时,可以最大限度的发挥app的刷新率

获取手机的当前充电状态

//It is very easy to subscribe to changes to the battery state,but you can get the current
//state by simply passing null in as your receiver.Nifty,isn't that?
IntentFilter filter=new IntentFilter(Intent.ACTION_BATTERY_CHANGED);
Intent batteryStatus=this.registerReceiver(null,filter);
int chargePlug=batteryStatus.getIntExtra(BatteryManager.EXTRA_PLUGGED,-1);
boolean acCharge=(chargePlug==BatteryManager.BATTERY_PLUGGED_AC);
if(acCharge){
    Log.v(LOG_TAG,“Thephoneischarging!”);
}

优化的建议

  • 任何App包括后台Service应该尽可能减少唤醒CPU的次数
  • 每次唤醒CPU执行的代码应该尽可能少,从而让CPU迅速恢复休眠
  • Wi-Fi比2G、3G更省电
  • 尽量在Wi-Fi下传输数据,在有Wi-Fi的时候做预加载,比如应用中心的zip包、离线资源等
  • 非Wi-Fi下,尽量减少网络访问,每一次后台交互都要考虑是否必须
  • 使用推送,代替循环请求
  • 对于自定义控件,通过canvas.clipRect()来帮助系统识别那些可见的区域,这个方法可以指定一块矩形区域,只有在这个区域内才会被绘制,其他的区域会被忽视
  • 避免嵌套太多层控件
  • 合理使用include、merge
  • 避免大量对象被创建又在短时间内马上被释放
  • 避免在for循环,onDraw中创建对象,无法避免的可以创建对象池,然后在不使用的时候释放
  • JobScheduler API会根据当前的情况与任务,组合出理想的唤醒时间,例如等到正在充电或者连接到WiFi的时候,或者集中任务一起执行,可以通过这个API实现很多免费的调度算法
//示例
public class MyJobService extendsJ obService{
    private static final String LOG_TAG="MyJobService";

    @Override
    public void onCreate(){
        super.onCreate();
        Log.i(LOG_TAG,"MyJobServi cecreated");
    }

    @Override
    public voidon Destroy(){
        super.onDestroy();
        Log.i(LOG_TAG,"MyJobService destroyed");
    }

    @Override
    public boolean onStartJob(JobParameters params){
        //This is where you would implement all of the logic for your job.Note that this runs
        //on the main thread,so you will want to use as eparate thread for asynchronous work
        //(as we demonstrate below to establishanet work connection).
        //If you use as eparatethread,return true to indicate that you need a "reschedule" to
        //return to the job at somepoint in the future to finish processing the work.Otherwise,
        //return false whenfinished.
        Log.i(LOG_TAG,"Totally and completely working on job"+params.getJobId());
        //First,check the network,and  the nattempt to connect.
        if(isNetworkConnected()){
            new SimpleDownloadTask().execute(params);
            return true;
        }else{
            Log.i(LOG_TAG,"No connection on job"+params.getJobId()+";sad face");
        }
        return false;
    }

    @Override
    public boolean onStopJob(JobParameters params){
        //Called if the job must be stopped before job Finished() has been called.This may
        //happen if the requirements are no longer being met,such as the user no longer
        //connecting to WiFi,or the device no longer being idle.Use this callback to resolve
        //anything that may cause your application to mis behave from the job being halted.
        //Return true if the job should be rescheduled based on there try criteria specified
        //when the job was created or return false to drop the job.Regardless of the value
        //returned,your job must stop executing.
        Log.i(LOG_TAG,"Whelp,something changed,so I'm callingiton job"+params.getJobId());
        return false;
    }

    /**
    *Determines if the device is currently on line.
    */
    private boolean isNetworkConnected(){
        ConnectivityManager connectivityManager=
        (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo networkInfo=connectivityManager.getActiveNetworkInfo();
        return(networkInfo!=null&&networkInfo.isConnected());
    }

    /**
    *Uses AsyncTask to create a task away from the mainUIthread.This task creates a
    *HTTPUrlConnection,and then downloads the content soft heweb page as an InputStream.
    *The InputStream is then converted to a String,which is logged by the
    *onPostExecute() method.
    */
    private class SimpleDownloadTask extends AsyncTask<JobParameters,Void,String>{

    protected JobParameters mJobParam;

    @Override
    protected String doInBackground(JobParameters...params){
        //cache system provided job requirements
        mJobParam=params[0];
        try{
            InputStreamis=null;
            //Only display the first 50 characters of the retrieved webpage content.
            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");
            //Starts the query
            conn.connect();
            int response=conn.getResponseCode();
            Log.d(LOG_TAG,"Theresponseis:"+response);
            is=conn.getInputStream();

            //Convert the input stream toastring
            Reader reader=null;
            reader=new InputStreamReader(is,"UTF-8");
            char[] buffer=new char[len];
            reader.read(buffer);
            return newString(buffer);

            }catch(IOExceptione){
                return"Unabletoretrievewebpage.";
            }
        }

    @Override
    protected void onPostExecute(Stringresult){
        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(Bundle savedInstanceState){
        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 theButtonThatWakelocks=(Button)findViewById(R.id.wakelock_poll);
        theButtonThatWakelocks.setText(R.string.poll_server_button);

        theButtonThatWakelocks.setOnClickListener(newView.OnClickListener(){
            @Override
            publicvoidonClick(Viewv){
                pollServer();
            }
        });
    }

    /**
        *This method polls the server via the JobScheduler API.By scheduling the job with this API,
                *your app can be confident it will execute,but without the need for awakelock.Rather,the
        *API will take your networkjobs and execute the min batch to best take advantage of the
        *initial network connection cost.
        *
        *The JobScheduler API works through a background service.In this sample,we have
        *a simple service in MyJobService to get you started.The job isscheduled here in
        *the activity,but the jobit self is executed in MyJobService in the start Job() method.For
        *example,to poll your server,you would create the network connection,send your GET
        *request,and then process the response all in MyJobService.This allows the JobScheduler API
        *to invoke your logic without neededtore start your activity.
        *
        *For brevity in the sample,we are scheduling the same jobsever alt imes in quick succession,
        *but again,try to consider similar task so ccurring over time in your applicationth at can
        *afford towait and maybe nefit from batching.
        */
        publicvoidpollServer(){
            JobScheduler scheduler=(JobScheduler)getSystemService(Context.JOB_SCHEDULER_SERVICE);
            for(inti=0;i<10;i++){
                JobInfo jobInfo=new JobInfo.Builder(i,mServiceComponent)
                    .setMinimumLatency(5000)//5seconds
                    .setOverrideDeadline(60000)//60seconds(forbrevityinthesample)
                    .setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY)//WiFiordataconnections
                    .build();

                mWakeLockMsg.append("Schedulingjob"+i+"!n");
                scheduler.schedule(jobInfo);
            }
        }
    }
  • 在移动网络下,最好做到批量执行网络请求,尽量避免频繁的间隔网络请求