Привет товарищи по цветам. У меня есть проблема с BroadcastReciever - есть, я знаю, что существует множество вопросов и ответов, потому что я пробовал каждый из них в течение последних 2 дней, поэтому, пожалуйста, если вы хотите пометить это как дублирующую проверку, что код не ' не соответствует тому, что я уже написал (поскольку я почти наверняка скопировал его из SO-ответа).
И вот мы здесь:
Я хочу обнаружить, что экран блокировки включается или выключается в моем базовом упражнении, из которого выходят все остальные мои действия
public abstract class BaseActivity extends AppCompatActivity{////
здесь у меня есть переменные-члены
BroadcastReceiver receiver;
IntentFilter filter;
который я назначаю так:
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//do some code
} else {
//do something else
}
}
};
filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
Это работает, как и ожидалось, если я поместил его в onCreate()
или onResume()
и я могу успешно вызвать registerReceiver(receiver, filter)
либо создать, либо возобновить, и это работает нормально.
Я не хочу, чтобы это было активным, когда приложение приостановлено, так как все различные ответы и руководства предлагают мне отменить его регистрацию в onPause
@Override
protected void onPause() {
//I have commented both out to demonstrate that I have tried both before and after the calling the superclass
// this.unregisterReceiver(receiver);
super.onPause();
// unregisterReceiver(receiver);
}
Когда я включаю этот незарегистрированный звонок, регистрация прекращается. Я попытался зарегистрироваться в OnCreate, OnResume и оба. Я могу перемещаться по комбинации в течение всего действия, но как только я ввожу отмену регистрации, она вообще не работает - даже ошибка или сбой (в противном случае я бы включил здесь трассировку стека).
Закрытие, которое я смог достичь, это:
receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() != null && intent.getAction().equals(Intent.ACTION_SCREEN_OFF)) {
//do some code
unregisterReceiver(receiver);
поместив незарегистрированную запись в onRecieve, я могу отменить регистрацию получателя и перерегистрировать его правильно, за исключением того, что, если у меня есть несколько действий в стеке для моего приложения, я получаю ошибку утечки памяти и запросы трассировки, скорее, если я забыли добавить незарегистрированный звонок.
Так есть ли у кого-нибудь идеи, почему добавление незарегистрированного вызова в onPause() приведет к полной отмене получателя?
Я предлагаю отложить отмену регистрации на несколько раз, и я попытался в течение 1 секунды, и это работает.
override fun onResume() {
super.onResume()
registerReceiver(broadcast, IntentFilter().apply {
addAction(Intent.ACTION_SCREEN_ON)
addAction(Intent.ACTION_SCREEN_OFF)
})
}
override fun onPause() {
super.onPause()
Handler().postDelayed({
unregisterReceiver(broadcast)
}, 1000)
}
Как я и думал, у вас есть эта проблема, потому что система отправляет ACTION_SCREEN_OFF после onStop()
, поэтому вы не можете обработать его, потому что вы уже зарегистрировали его. Не знаю, почему вы не можете обработать событие SCREEN_ON, потому что, когда я проверял это, я вижу, что система отправляет его после onResume()
. Вот что у меня в журналах:
D/TEST: onPause:
D/TEST: onStop:
D/TEST: onReceive: action = android.intent.action.SCREEN_OFF
D/TEST: onStart:
D/TEST: onResume:
D/TEST: onReceive: action = android.intent.action.SCREEN_ON
Я думаю, оно было отправлено раньше, чем onResume
, но доставлено после него.
Итак, мое решение состоит в том, чтобы зарегистрировать получатель в onCreate(@Nullable Bundle savedInstanceState)
и onDestroy()
регистрацию в onDestroy()
, вот как я получил эти журналы.
Обновление 1: так я зарегистрировал получателя в onCreate(@Nullable Bundle savedInstanceState)
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
registerReceiver(new TestReceiver(), filter);
Обновление 2: я пропустил, что вам не нужно получать события, если ваша активность приостановлена. Если есть какой-то код, который вы не хотите выполнять, когда действие приостановлено, я могу предложить вам создать простой enum:
enum ActivityState {НАЧИНАЕТСЯ, ВОЗОБНОВЛЕНО, ПРИОСТАНОВЛЕНО, ОСТАНОВЛЕНО}
и закрытая переменная ActivityState currentState
. Затем в методах жизненного цикла присваивайте правильное состояние currentState. Затем в onReceive()
вашего приемника вы можете проверить текущее состояние и сделать то, что вы хотите, в зависимости от состояния. Журналы, когда приложение активно:
D/TEST: onReceive: action = android.intent.action.SCREEN_OFF, current Activity state = STOPED
D/TEST: onReceive: action = android.intent.action.SCREEN_ON, current Activity state = RESUMED
И логи, когда приложение не было активным:
D/TEST: onReceive: action = android.intent.action.SCREEN_OFF, current Activity state = STOPED
D/TEST: onReceive: action = android.intent.action.SCREEN_ON, current Activity state = STOPED
Я надеюсь, что это помогает!