android的电量一直是所有人关注的问题,
电池越来越大,使用起来没有任何改善,有人觉得是屏幕越来越大导致的,但是实际上更多的是app的不注意,导致的浪费了很多电量。
从本章开始,我们将从开发的角度来告诉大家,如何使我们的应用更加省电的一些技巧。
JobSchedule
这个是Android 5.0之后,考虑到截止我写这篇文章的时候,Android 5.0以上的用户已经增加到25.1%,我觉的在开发中,建议使用JobSchedule来规范我们的开发。
功能:JobSchedule的作用就是将我们需要定时或者特定条件的事件交给系统,当系统满足条件的时候,就会回调我们的组件,运行我们的代码,并且在执行的过程中会回调我们的方法,
条件:在刚刚我说了在特定条件,这个当然不是随便的条件,而是规定好的,(我总结了4+1种条件)
条件1:网络可用
条件2:定时
条件3:手机处于空闲状态
条件4:手机是否处于供电稳定状态(充电)
这个也并非只是插入充电器,而且还要在电池处于健康状态的情况下才会触发,一般来说是手机电量>15%
条件+1:循环执行(被列入+1是因为这个需要前四个触发之后才有用处,当然你也可以把它归为定时)
使用方法:
ComponentName mServiceComponent = new ComponentName(this, TestJobService.class); //当事件满足的时候,调用的组件
JobInfo.Builder builder = new JobInfo.Builder(i, mServiceComponent); //i为int值,当前事件的
JobScheduler tm =(JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE);
tm.schedule(builder);
这里只是一个使用的最小模型,他并不会有任何的触发条件,因为我们还没有添加,(这只是例子啊,你如果真的这么写,直接就抛出异常了,因为不允许不设置任何条件,这样没意义)
下面依次对每一种触发进行设置:
网络触发:
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); //设置为不限制流量的条件触发,可以认为是wifi条件下触发
builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); //有网络连接的时候触发
定时:
builder.setOverrideDeadline(time); //其实这里与我们所想的用法又有所区别,他并没有单独提供接口,而是复用,这个方法在后面有另一种用法的介绍。
手机处于空闲状态:
builder.setRequiresDeviceIdle(true/*false*/); //设置为空闲状态触发
手机是否处于供电稳定状态
builder.setRequiresCharging(true/*false*/); //手机是否处于充电状态
除了这些条件之外还可以进行一些其他的设置来控制触发状态
builder.setMinimumLatency(time); //time的单位是s,作用是满足触发条件也要延时time 豪秒之后再触发
builder.setOverrideDeadline(time); //time的单位是s,作用是设置time豪秒之后,如果没有任何触发也执行
builder.setPeriodic(time); //设置循环触发,否则触发一次就结束了,这样可以间隔time豪秒之后,还是可以触发
builder.setPersisted(true/*false*/); //设置触发条件是否重启手机后仍有效。 /这个它是通过将presist的信息,写到了/data/system/job/jobs.xml文件中了
builder.setExtras(PersistableBundle extra); //设置startJob时,带有Bundle
builder.setBackoffCriteria(Long.valueOf(backoffTime) * 1000, backoffPolicy); //这个是比较特殊的,这个是当意外发生的时候,多久之后,重新执行,分为线性计算和指数计算,
综上就是JobSchedule的基本使用方法,下面我来展示一下Google所给的官方示例:
/* * Copyright 2014 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.jobscheduler.service; import android.app.job.JobInfo; import android.app.job.JobScheduler; import android.app.job.JobParameters; import android.app.job.JobService; import android.content.Context; import android.content.Intent; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; import com.example.android.jobscheduler.MainActivity; import java.util.LinkedList; /** * Service to handle callbacks from the JobScheduler. Requests scheduled with the JobScheduler * ultimately land on this service's "onStartJob" method. Currently all this does is post a message * to the app's main activity to change the state of the UI. */ public class TestJobService extends JobService { private static final String TAG = "SyncService"; @Override public void onCreate() { super.onCreate(); Log.i(TAG, "Service created"); } @Override public void onDestroy() { super.onDestroy(); Log.i(TAG, "Service destroyed"); } /** * When the app's MainActivity is created, it starts this service. This is so that the * activity and this service can communicate back and forth. See "setUiCalback()" */ @Override public int onStartCommand(Intent intent, int flags, int startId) { Messenger callback = intent.getParcelableExtra("messenger"); Message m = Message.obtain(); m.what = MainActivity.MSG_SERVICE_OBJ; m.obj = this; try { callback.send(m); } catch (RemoteException e) { Log.e(TAG, "Error passing service object back to activity."); } return START_NOT_STICKY; } @Override public boolean onStartJob(JobParameters params) { // We don't do any real 'work' in this sample app. All we'll // do is track which jobs have landed on our service, and // update the UI accordingly. jobParamsMap.add(params); if (mActivity != null) { mActivity.onReceivedStartJob(params); } Log.i(TAG, "on start job: " + params.getJobId()); return true; } @Override public boolean onStopJob(JobParameters params) { // Stop tracking these job parameters, as we've 'finished' executing. jobParamsMap.remove(params); if (mActivity != null) { mActivity.onReceivedStopJob(); } Log.i(TAG, "on stop job: " + params.getJobId()); return true; } MainActivity mActivity; private final LinkedList<JobParameters> jobParamsMap = new LinkedList<JobParameters>(); public void setUiCallback(MainActivity activity) { mActivity = activity; } /** Send job to the JobScheduler. */ public void scheduleJob(JobInfo t) { Log.d(TAG, "Scheduling job"); JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); tm.schedule(t); } /** * Not currently used, but as an exercise you can hook this * up to a button in the UI to finish a job that has landed * in onStartJob(). */ public boolean callJobFinished() { JobParameters params = jobParamsMap.poll(); if (params == null) { return false; } else { jobFinished(params, false); return true; } } }
/* * Copyright 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.jobscheduler; import android.app.Activity; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.res.Resources; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.os.Messenger; import android.text.TextUtils; import android.view.View; import android.widget.CheckBox; import android.widget.EditText; import android.widget.RadioButton; import android.widget.TextView; import android.widget.Toast; import com.example.android.jobscheduler.service.TestJobService; public class MainActivity extends Activity { private static final String TAG = "MainActivity"; public static final int MSG_UNCOLOUR_START = 0; public static final int MSG_UNCOLOUR_STOP = 1; public static final int MSG_SERVICE_OBJ = 2; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.sample_main); Resources res = getResources(); defaultColor = res.getColor(R.color.none_received); startJobColor = res.getColor(R.color.start_received); stopJobColor = res.getColor(R.color.stop_received); // Set up UI. mShowStartView = (TextView) findViewById(R.id.onstart_textview); mShowStopView = (TextView) findViewById(R.id.onstop_textview); mParamsTextView = (TextView) findViewById(R.id.task_params); mDelayEditText = (EditText) findViewById(R.id.delay_time); mDeadlineEditText = (EditText) findViewById(R.id.deadline_time); mWiFiConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_unmetered); mAnyConnectivityRadioButton = (RadioButton) findViewById(R.id.checkbox_any); mRequiresChargingCheckBox = (CheckBox) findViewById(R.id.checkbox_charging); mRequiresIdleCheckbox = (CheckBox) findViewById(R.id.checkbox_idle); mServiceComponent = new ComponentName(this, TestJobService.class); // Start service and provide it a way to communicate with us. Intent startServiceIntent = new Intent(this, TestJobService.class); startServiceIntent.putExtra("messenger", new Messenger(mHandler)); startService(startServiceIntent); } // UI fields. int defaultColor; int startJobColor; int stopJobColor; private TextView mShowStartView; private TextView mShowStopView; private TextView mParamsTextView; private EditText mDelayEditText; private EditText mDeadlineEditText; private RadioButton mWiFiConnectivityRadioButton; private RadioButton mAnyConnectivityRadioButton; private CheckBox mRequiresChargingCheckBox; private CheckBox mRequiresIdleCheckbox; ComponentName mServiceComponent; /** Service object to interact scheduled jobs. */ TestJobService mTestService; private static int kJobId = 0; Handler mHandler = new Handler(/* default looper */) { @Override public void handleMessage(Message msg) { switch (msg.what) { case MSG_UNCOLOUR_START: mShowStartView.setBackgroundColor(defaultColor); break; case MSG_UNCOLOUR_STOP: mShowStopView.setBackgroundColor(defaultColor); break; case MSG_SERVICE_OBJ: mTestService = (TestJobService) msg.obj; mTestService.setUiCallback(MainActivity.this); } } }; private boolean ensureTestService() { if (mTestService == null) { Toast.makeText(MainActivity.this, "Service null, never got callback?", Toast.LENGTH_SHORT).show(); return false; } return true; } /** * UI onclick listener to schedule a job. What this job is is defined in * TestJobService#scheduleJob(). */ public void scheduleJob(View v) { if (!ensureTestService()) { return; } JobInfo.Builder builder = new JobInfo.Builder(kJobId++, mServiceComponent); String delay = mDelayEditText.getText().toString(); if (delay != null && !TextUtils.isEmpty(delay)) { builder.setMinimumLatency(Long.valueOf(delay) * 1000); } String deadline = mDeadlineEditText.getText().toString(); if (deadline != null && !TextUtils.isEmpty(deadline)) { builder.setOverrideDeadline(Long.valueOf(deadline) * 1000); } boolean requiresUnmetered = mWiFiConnectivityRadioButton.isChecked(); boolean requiresAnyConnectivity = mAnyConnectivityRadioButton.isChecked(); if (requiresUnmetered) { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED); } else if (requiresAnyConnectivity) { builder.setRequiredNetworkType(JobInfo.NETWORK_TYPE_ANY); } builder.setRequiresDeviceIdle(mRequiresIdleCheckbox.isChecked()); builder.setRequiresCharging(mRequiresChargingCheckBox.isChecked()); mTestService.scheduleJob(builder.build()); } public void cancelAllJobs(View v) { JobScheduler tm = (JobScheduler) getSystemService(Context.JOB_SCHEDULER_SERVICE); tm.cancelAll(); } /** * UI onclick listener to call jobFinished() in our service. */ public void finishJob(View v) { if (!ensureTestService()) { return; } mTestService.callJobFinished(); mParamsTextView.setText(""); } /** * Receives callback from the service when a job has landed * on the app. Colours the UI and post a message to * uncolour it after a second. */ public void onReceivedStartJob(JobParameters params) { mShowStartView.setBackgroundColor(startJobColor); Message m = Message.obtain(mHandler, MSG_UNCOLOUR_START); mHandler.sendMessageDelayed(m, 1000L); // uncolour in 1 second. mParamsTextView.setText("Executing: " + params.getJobId() + " " + params.getExtras()); } /** * Receives callback from the service when a job that * previously landed on the app must stop executing. * Colours the UI and post a message to uncolour it after a * second. */ public void onReceivedStopJob() { mShowStopView.setBackgroundColor(stopJobColor); Message m = Message.obtain(mHandler, MSG_UNCOLOUR_STOP); mHandler.sendMessageDelayed(m, 2000L); // uncolour in 1 second. mParamsTextView.setText(""); } }