Rock with Android


Service和BroadcastReceiver

安卓本身是一个多任务的系统,所以可以有真正的后台服务存在。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通信。具体做法可以是下面的方法:

  1. Client调用Service接口,直接返回,然后Client起BroadcastReceiver,等Service异步操作完,发广播得到结果。
  2. Client和Service都使用BroadcastReceiver,使用广播互发消息。这个方案因为都是使用广播,会增大延时,并且Intent本身数据有大小限制,太大的数据没法直接传递。

BroadcastReceiver

BroadcastReceiver可以在manifest里面声明,也可以在代码里直接使用 Context.registerReceiver()动态注册。典型的使用可以是Activity和Service通讯,也可以是Activity间互相通讯,还可以是不同应用间通讯。因为使用方便和灵活,容易被滥用。

  1. 在Activity中,如果在onResume中注册,那么需要在onPause里注销,减少系统开销。
  2. 如果在onReceive里的操作比较耗时,或者希望Receiver的有更长的生命周期,需要和Service一起配合使用。

在安卓的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

IntentService有点类似AsyncTask,也是运行在独立线程里,不会阻塞UI线程,可以看成是一种轻量级的Service。通过调用startService(Intent) 来调用IntentService,在onHandleIntent(Intent)里面处理对应Intent,执行操作。

  1. 和Service不同的地方是,IntentService是需要时启动,处理完成后就退出的,并不真正后台长期存在
  2. IntentService同时只能处理一个请求,也就是说只会起一个工作线程
  3. IntentService适用于业务简单的后台单次或者重复性任务,Client只是调用,不需要等待结果的情况

AlarmManager

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

目录上一章适配