安卓本身是一个多任务的系统,所以可以有真正的后台服务存在。Service就是对应的封装类。
在实际中,典型的后台服务需求有播放,推送/同步数据,定时任务这些类型。前两者是使用典型的C/S结果的场景,而后者其实在安卓上面可以使用Alarm的机制来做到比较轻的方案,不用后台常驻一个服务。
如果希望服务是单独开一个进程的话,需要在manifest里使用下面的声明,":remote"标识该进程的名字,确切的讲是冒号后面是进程的名字。单独使用进程的好处是彻底和UI进程分开,但是也会有麻烦的地方,比如通讯是跨进程的,需要走AIDL接口,或者使用BroadcastReceiver监听广播,而且传输的数据大小也不能太大。所以除非有额外的好处,并不推荐单独起进程。
<service android:name=".app.SyncService" android:process=":remote" />
不单独开进程的话,Service本身默认也是在主线程里的,所以如果有耗时的计算或者IO操作,还是需要自己起线程或者使用AsyncTask来异步处理。
具体的例子可以参考Service的Local Service Sample部分。使用IBinder得到Service的Client,直接调用对应的接口,这样效率比较高。但是由于上面所说的异步处理的问题,所以直接调用Service的接口都是阻塞的,适用于返回结果的情况。
所以如果Service里面的操作比较耗时的话,就需要利用异步加回调的机制和Client通信。具体做法可以是下面的方法:
BroadcastReceiver可以在manifest里面声明,也可以在代码里直接使用 Context.registerReceiver()动态注册。典型的使用可以是Activity和Service通讯,也可以是Activity间互相通讯,还可以是不同应用间通讯。因为使用方便和灵活,容易被滥用。
在安卓的support包里,新加入了LocalBroadcastManager,对于应用内部需要使用广播的情况更加友好和高效了。
LocalBroadcastManager所发的广播,并且注册的Receiver的监听,都只是针对当前应用,所以从安全和性能都比全局的Receiver和广播要高的多。具体使用如下:
LocalBroadcastManager manager = LocalBroadcastManager.getInstance(context); manager.registerReceiver(receiver, filter); manager.sendBroadcast(intent); //如果有对应的Receiver相当于直接调用其onReceiver,所以会阻塞直到处理完成才返回 manager.sendBroadcastSync(intent); manager.unregisterReceiver(receiver);
IntentService有点类似AsyncTask,也是运行在独立线程里,不会阻塞UI线程,可以看成是一种轻量级的Service。通过调用startService(Intent) 来调用IntentService,在onHandleIntent(Intent)里面处理对应Intent,执行操作。
AlarmManager提供了系统闹钟服务的接口,利用闹钟服务,可以达到Cron的效果。一般可以和IntentService搭配使用,比如定时后台同步数据,定时清理临时文件等操作。
AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Intent intent = new Intent(context, SyncService.class); PendingIntent pIntent = PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT); am.setRepeating(AlarmManager.RTC_WAKEUP, System.currentTimeMillis() + 2*60*1000, 2*60*1000, pIntent);