服务中的广播接收器

92

我正在尝试在一个Service内启动一个BroadcastReceiver。我的目标是让后台运行的service收集到来的短信和记录来电。我觉得最好的方法是使用一个包含广播接收器的service来实现这一点。

我该如何做?我已经有了正在运行的服务。

2个回答

132

既然您的服务已经设置好了,那么只需在您的服务中添加一个广播接收器:

private final BroadcastReceiver receiver = new BroadcastReceiver() {
   @Override
   public void onReceive(Context context, Intent intent) {
      String action = intent.getAction();
      if(action.equals("android.provider.Telephony.SMS_RECEIVED")){
        //action for sms received
      }
      else if(action.equals(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED)){
           //action for phone state changed
      }     
   }
};

在你的服务的onCreate方法中这样做:

IntentFilter filter = new IntentFilter();
filter.addAction("android.provider.Telephony.SMS_RECEIVED");
filter.addAction(android.telephony.TelephonyManager.ACTION_PHONE_STATE_CHANGED);
filter.addAction("your_action_strings"); //further more
filter.addAction("your_action_strings"); //further more

registerReceiver(receiver, filter);

在你的服务的 onDestroy 方法中:

unregisterReceiver(receiver);

然后,您就可以开始接收在 onCreate 中提到的任何过滤器的广播。请确保添加任何必要的权限,例如:

<uses-permission android:name="android.permission.RECEIVE_SMS" />

1
我注意到在发送sendBroadcast(intent)时无法通过intent.setData(myUri)传递数据,而广播接收器在这种情况下也不起作用,这是正确的吗? - deadfish
2
@waqaslam,你在清单文件中设置了这个广播接收器吗? - IgorGanapolsky
3
不需要在清单文件中注册这些接收器。 - waqaslam
嘿,我想问一下,如果我在Service中定义BroadcastReceiver而不是在MainActivity中定义,那么它会消耗更多的电池吗?因为单个应用程序有两个进程正在运行。或者我的应用程序在设备上消耗的电池和内存将保持不变。 - user10351180
2
@SayyedRizwan 您的服务和广播接收器将在同一进程中运行,很可能是同一个线程(除非您创建了一个新线程)。电池消耗取决于您如何定义线程(后台/前台)以及广播的数量。 - waqaslam
显示剩余6条评论

26
更好的模式是创建一个独立的 BroadcastReceiver。这样可以确保您的应用程序能够响应广播,无论 Service 是否正在运行。事实上,使用此模式可能完全消除对常驻运行的 Service 的需求。
在清单文件中注册 BroadcastReceiver,并为其创建一个单独的类/文件。
例如:
<receiver android:name=".FooReceiver" >
    <intent-filter >
        <action android:name="android.provider.Telephony.SMS_RECEIVED" />
    </intent-filter>
</receiver>

当接收器运行时,您只需将一个IntentBundle)传递给Service,并在onStartCommand()中响应它。

例如:

public class FooReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        // do your work quickly!
        // then call context.startService();
    }   
}

7
我希望广播在服务的生命周期内,这样应用程序只会根据服务时间轴查询消息/电话。这种方法能够实现吗?看起来你已经设置好了接收广播以启动服务。 - Utopia025
如果服务尚未运行,则此实现将启动“Service”,否则传递新的“Intent”以在“onStartCommand”中检索。如果您只想在“Service”处于活动状态时运行它,则可以通过“PackageManager”的“setComponentEnabledSetting()”编程方式启用/禁用“Receiver”组件。 - Paul Burke
4
如果您只想在“服务”运行时使“接收器”保持活动状态,那么Waqas的答案可能是您最好的选择。 - Paul Burke
3
如果您没有一个Activity,那么API 3.1及更高版本将无法使用:http://ashimita.blogspot.com.tr/2012/04/broadcast-receiver-change-in-flow-since.html - elif
2
从Android 3.1开始,如果相应的应用程序从未由用户启动过或者用户通过Android菜单显式停止了应用程序,则Android系统默认情况下排除所有接收器接收意图。http://www.vogella.com/tutorials/AndroidBroadcastReceiver/article.html - Juraj Petrik
问题在于当你杀死应用程序时,广播接收器将自动停止,并且应用程序在此之后将无法工作。 - pavel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接