• QQ
  • nahooten@sina.com
  • 常州市九洲新世界花苑15-2

Android

android service 后台执行按时使命

原创内容,转载请注明原文网址:http://homeqin.cn/a/wenzhangboke/jishutiandi/Android/2019/0603/526.html

 

 

起首说说android中的按时使命

 

Android 中的按时使命普通有两种实现体例,一种是应用Java API 里提供的Timer 类,一种是应用Android 的Alarm 机制。

 

这两种体例在无数环境下都能实现相似的结果,但Timer有一个明显的短板,它并不太适合于那些必要永远在后台运转的按时使命。我们都晓得,为了能让电池加倍耐用,每种手机都会有本人的休眠策略,Android 手机就会在长时间不操纵的环境下自动让CPU 进入到睡眠状况,这就有可能招致Timer 中的按时使命无法平常运转。而Alarm 机制则不存在这种环境,它具备唤醒CPU 的功效,即可以包管每次必要执行按时使命的时候CPU 都能平常事情。必要留意,这里唤醒CPU 和唤醒屏幕彻底不是统一个概念,万万不要发生殽杂。

辣么起首我们来看一下Alarm 机制的用法吧, 其实并不复杂, 主要即是借助了AlarmManager 类来实现的。这个类和NotificationManager 有点相似,都是通过挪用Context 的

getSystemService()要领来获取实例的,只是这里必要传入的参数是Context.ALARM_SERVICE。是以,获取一个AlarmManager 的实例便写成:

 

AlarmManager manager = (AlarmManager) getSystemService(Context.ALARM_SERVICE);

 

接下来挪用AlarmManager 的set()要领便配置一个按时使命了,好比说想要设定一个使命在10 秒钟行,便写成:

 

long triggerAtTime = SystemClock.elapsedRealtime() + 10 * 1000;

 

manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime,pendingIntent);

 

上头的两行代码你不必然能看得清晰,由于set()要领中必要传入的三个参数略微有点复杂,下面我们就来周密地阐发一下。

 

第一个参数是一个整型参数,用于指定AlarmManager 的事情范例,有四种值可选,分别是ELAPSED_REALTIME、ELAPSED_REALTIME_WAKEUP、RTC 和RTC_WAKEUP。此中ELAPSED_REALTIME 表示让按时使命的触发时间从体系开机开始算起,但不会唤醒CPU。ELAPSED_REALTIME_WAKEUP 一样表示让按时使命的触发时间从体系开机开始算起,但会唤醒CPU。RTC 表示让按时使命的触发时间从1970 年1月1 日0 点开始算起,但不会唤醒CPU。RTC_WAKEUP 一样表示让按时使命的触发时间从1970 年1 月1 日0 点开始算起,但会唤醒CPU。应用SystemClock.elapsedRealtime()要领可以获取到体系开机至今所通过时间的毫秒数,应用System.currentTimeMillis()要领可以获取到1970 年1 月1 日0 点至今所通过时间的毫秒数。

 

而后看一下第二个参数,这个参数就好明白多了,即是按时使命触发的时间,以毫秒为单元。要是第一个参数应用的是ELAPSED_REALTIME 或ELAPSED_REALTIME_WAKEUP,则这里传入开机至今的时间再加上延迟执行的时间。要是第一个参数应用的是RTC 或RTC_WAKEUP,则这里传入1970 年1 月1 日0 点至今的时间再加上延迟执行的时间。

 

第三个参数是一个PendingIntent,对于它你应该曾经不会目生了吧。这里我们普通会挪用getBroadcast()要领来获取一个能够执行播送的PendingIntent。如许当按时使命被触发的时候,播送汲取器的onReceive()要领便获得执行。打听了set()要领的每个参数以后,你应该能想到,设定一个使命在10 秒钟后执行还可以写成:

long triggerAtTime = System.currentTimeMillis() + 10 * 1000;

manager.set(AlarmManager.RTC_WAKEUP, triggerAtTime, pendingIntent);

 

好了,当今你曾经掌握Alarm 机制的根基用法,下面我们就来建立一个可以永远在后台执行按时使命的服无。建立一个ServiceBestPractice 名目,而后新增一个LongRunningService类,代码如下所示:

public class LongRunningService extends Service {

@Override

public IBinder onBind(Intent intent) {

return null;

}

@Override

public int onStartCo妹妹and(Intent intent, int flags, int startId) {

new Thread(new Runnable() {

@Override

public void run() {

Log.d("LongRunningService", "executed at " + new Date().

toString());

}

}).start();

AlarmManager manager = (AlarmManager) getSystemService(ALARM_SERVICE);

int anHour = 60 * 60 * 1000; // 这是一小时的毫秒数

long triggerAtTime = SystemClock.elapsedRealtime() + anHour;

Intent i = new Intent(this, AlarmReceiver.class);

PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, 0);

manager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP, triggerAtTime, pi);

return super.onStartCo妹妹and(intent, flags, startId);

}

}

我们在onStartCo妹妹and()要领里开启了一个子线程,而后在子线程里便执行具体的逻辑操纵了。这里简单起见,只是打印了一下目前的时间。

建立线程以后的代码即是我们方才疏解的Alarm 机制的用法了, 先是获取到了

AlarmManager 的实例,而后定义使命的触发时间为一小时后,再应用PendingIntent 指定处

理按时使命的播送汲取器为AlarmReceiver,末了挪用set()要领实现设定。

显然,AlarmReceiver 目前还不存在呢,所以下一步即是要新建一个AlarmReceiver 类,

并让它秉承自BroadcastReceiver,代码如下所示:

public class AlarmReceiver extends BroadcastReceiver {

@Override

public void onReceive(Context context, Intent intent) {

Intent i = new Intent(context, LongRunningService.class);

context.startService(i);

}

}

onReceive()要领里的代码最简单,即是构建出了一个Intent 工具,而后去启动LongRunningService 这个服无。辣么这里为何要如许写呢?其实在人不知,鬼不觉中,这就曾经

将一个永远在后台按时运转的服无实现了。由于一旦启动LongRunningService,就会在onStartCo妹妹and()要领里设定一个按时使命,如许一小时后AlarmReceiver 的onReceive()要领就将获得执行,而后我们在这里再次启动LongRunningService,如许就形成了一个永远的轮回,包管LongRunningService 可以每隔一小时就会启动一次,一个永远在后台按时运转的服无天然也就实现了。接下来的使命也很明白了,即是我们必要在翻开程序的时候启动一次LongRunningService,

以后LongRunningService 便一直运转了。点窜MainActivity 中的代码,如下所示:

public class MainActivity extends Activity {

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

Intent intent = new Intent(this, LongRunningService.class);

startService(intent);

}

}

末了别忘了,我们所用到的服无和播送汲取器都要在AndroidManifest.xml 中注册才行代码如下所示:

 

package="com.example.servicebestpractice"

android:versionCode="1"

android:versionName="1.0" >

……

<application

android:allowBackup="true"

android:icon="@drawable/ic_launcher"

android:label="@string/app_name"

android:theme="@style/AppTheme" >

<activity

android:name="com.example.servicebestpractice.MainActivity"

android:label="@string/app_name" >

<intent-filter>

<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />

</intent-filter>

</activity>

<service android:name=".LongRunningService" >

</service>

<receiver android:name=".AlarmReceiver" >

</receiver>

</application>

</manifest>

 

 

 

当今便来运转一下程序了。固然你不会在界面上看到任何有用的信息,但现实上LongRunningService 曾经在后台暗暗地运转起来了。为了能够验证一下运转后果,我将手机闲置了几个小时,而后调查LogCat 中的打印日记

 

 

 

可以看到,LongRunningService 公然如我们所愿地运转着,每隔一小时都会打印一条日记。如许,当你真正必要去执行某个按时使命的时候,只必要将打印日记替代成具体的使命逻辑就行了。

另外必要留意的是,从Android 4.4 版本开始,Alarm 使命的触发时间将会变得禁止确,有可能会延迟一段时间后使命才气获得执行。这并不是个bug,而是体系在耗电性方面进行的优化。体系会自动检测目前有几许Alarm 使命存在,而后将触发时间快要的几个使命放在一路执行,这便大幅度地削减CPU 被唤醒的次数,从而有用延伸电池的应用时间。固然,要是你要求Alarm 使命的执行时间必需筹办无误,Android 仍旧提供打听决计划。应用AlarmManager 的setExact()要领来替代set()要领,便包管使命准时执行了。

 

所有内容来自《第一行代码》请支持原作者

 

上篇:上一篇:Android 之 SeekBar用法介绍
下篇:下一篇:AccessibilityEvent type