我试图创建一个应用程序,允许用户在设定的时间间隔内或手动静音设备。我也希望用户能够输入更复杂的规则,如静音手机只有当连接到某个WiFi网络,蓝牙设备或当进入一个地理位置。在静默模式,但是,我希望允许用户创建联系人列表,电话应该仍然响。
为此,我创建了一个前台服务,在其中注册一个广播接收器。然而,在活动离开前台仅仅几分钟后,接收器就会准时停止工作,并不时地更新。
这个问题发生在Android8的设备(华为/荣誉7X)上。
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
<uses-permission android:name="android.permission.BLUETOOTH"/>
<service android:name=".PhoneService"/>
启动服务的内部活动
//for the sake of simplicity, I omit the code where runtime permissions are requested
Intent foregroundIntent = new Intent(this, PhoneService.class);
foregroundIntent.putExtra(PhoneService.EXTRA_ACTION, PhoneService.ACTION_START);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
startForegroundService(foregroundIntent);
} else {
startService(foregroundIntent);
}
服务类别
public class PhoneService extends Service {
private static final String NOTIFICATION_CATEGORY = "notification_category";
private static final int NOTIFICATION_REQUEST_CODE = 0;
private static final String CHANNEL_ID = "test_channel";
private static final String CHANNEL_NAME = "test channel";
private static final int NOTIFICATION_ID = 1;
public static final String EXTRA_ACTION = "extra_action";
public static final String ACTION_START = "action_start";
public static final String ACTION_STOP = "action_stop";
private static final int STOP_ID = 2;
private int phoneReceiveCount = 0;
private int btReceiveCount = 0;
BroadcastReceiver phoneReceiver;
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
final IntentFilter intentFilter = new IntentFilter();
//adding some filters
intentFilter.addAction("android.intent.action.PHONE_STATE");
intentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
intentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
this.phoneReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
//update the count and show it in the notification body
//used only to see if the receiver works
String action = intent.getAction();
if (action != null && action.equals("android.intent.action.PHONE_STATE")) {
phoneReceiveCount++;
} else if (action != null && (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) || action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
btReceiveCount++;
}
createNotification(context);
}
};
registerReceiver(phoneReceiver, intentFilter);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getStringExtra(EXTRA_ACTION);
if (action.equals(ACTION_START)) {
createNotification(this);
} else if (action.equals(ACTION_STOP)) {
stopSelf();
}
//also tried with START_STICKY
return START_REDELIVER_INTENT;
}
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(phoneReceiver);
}
private void createNotification(Context context) {
//intent to open app
Intent entryActivityIntent = new Intent(context, MainActivity.class);
entryActivityIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingEntryActivityIntent = PendingIntent.getActivity(context, NOTIFICATION_REQUEST_CODE, entryActivityIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//intent to stop foreground service
Intent stopServiceIntent = new Intent(context, PhoneService.class);
stopServiceIntent.putExtra(PhoneService.EXTRA_ACTION, PhoneService.ACTION_STOP);
stopServiceIntent.addCategory(NOTIFICATION_CATEGORY);
PendingIntent pendingStopForeground = PendingIntent.getService(context, STOP_ID, stopServiceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
//build notification
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(
CHANNEL_ID,
CHANNEL_NAME,
NotificationManager.IMPORTANCE_LOW);
channel.enableVibration(false);
channel.enableLights(false);
notificationManager.createNotificationChannel(channel);
}
String contentText = "phoneReceiveCount: " + String.valueOf(phoneReceiveCount) + "\nbtReceiveCount: " + String.valueOf(btReceiveCount);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(context, CHANNEL_ID)
.setColor(ContextCompat.getColor(context, R.color.colorPrimary))
.setSmallIcon(R.drawable.ic_service_on)
.setContentTitle("This is the title")
.setContentText(contentText)
.addAction(R.drawable.ic_stop, "Stop", pendingStopForeground)
.setStyle(new NotificationCompat.BigTextStyle().bigText(contentText))
.setContentIntent(pendingEntryActivityIntent);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {
notificationBuilder.setPriority(NotificationCompat.PRIORITY_HIGH);
}
startForeground(NOTIFICATION_ID, notificationBuilder.build());
}
}
Android 8对后台服务有一定的限制,广播接收器等广播必须在运行时使用context.registerreceiver注册。
详解请看此链接:
https://developer.android.com/about/versions/oreo/backgroadcasts
我刚把Nexus5更新到Android6,直到现在我的应用程序还能正常工作,但现在广播接收器却不工作了。新版本有什么变化吗?这是我试过的在以前的版本上工作的代码,但在Marshmallow中不行- Android清单 同样,PHONE_STATE的广播接收器也不工作。
问题内容: 有人可以解释和之间的确切区别吗? 在什么情况下我们必须使用每个Receiver类? 问题答案: 和之间只有一个区别。 当您收到内部广播方法时, 假设, BroadcastReceiver : 它 不保证 该 CPU将保持清醒 ,如果你启动一些长时间运行的进程。CPU可能会立即回到睡眠状态。 WakefulBroadcastReceiver : 这是 保证 该 CPU将保持清醒 ,直到你
SMSlistener
我有一个broadcastreciever开始了一个长的操作(上传过程)。在一个从活动类开始的服务的代码中,我需要在一个新线程中注册这个接收器。 我已经检查了这篇文章Android的广播接收器是在一个新的线程中启动的吗?但是我需要一个关于使用Context.RegisterReceiver的更具体的示例(BroadcastReceiver receiver、IntentFilter filter、
大家听好了。首先,我的接收器不工作时,应用程序关闭在我的设备,因为自动启动管理器。我觉得自己很傻...当我试图解决它的时候,我学到了非常重要的东西。 首先,Android6.0许可请求广播接收器在Android6.0Marshmallow中不工作 更新:我还注意到,当应用程序运行和一切正常时,服务启动两次,停止两次。 服务启动时,我看到以下消息: > Toast.MakeText(上下文,“”+P