WakefulBroadcastReceiver意图不仅仅在某些情况下启动(奇怪)

时间:2014-12-05 14:31:04

标签: android android-intent broadcastreceiver

我的应用中发生了一个非常奇怪的错误。我正在构建一个警报APP,我正在使用SQLite存储警报数据和广播接收器来管理警报管理器调用。

在某些情况下,onReceive的代码奇怪地表现不一样。当接收器收到广播时,我尝试启动一个Activity,几乎90%的情况一切顺利,我设法启动Activity,但在某些情况下,接收器执行指令非常奇怪" startActivity(i)&# 34;但没有任何反应。

重现BUG真的很难,在我的调试过程中,我已经学会了我所提到的内容,但是对于我来说,理解在大多数情况下对startActivity()的调用是如何工作的,在某些情况下确实很困难。不行。我已经搜索了Stack社区,但是没有人接受这种问题,每个人在启动活动时都遇到了问题,因为他们没有设置标志,或者因为他们没有在清单中注册接收器。下面我发布了代码。

public class AlarmReceiver extends WakefulBroadcastReceiver {
    // The app's AlarmManager, which provides access to the system alarm services.
    private AlarmManager alarmMgr;
    // The pending intent that is triggered when the alarm fires.
    private PendingIntent alarmIntent;

    @Override
    public void onReceive(Context context, Intent intent) {
        Utils.logToFile("Received Alarm ,I am in onReceive(), ALARM ID: "+intent.getExtras().getInt(Constants.ALARM_ID));
        Intent intent = new Intent(context, StopAlarm.class);
        Bundle b = new Bundle();
        b.putInt(Constants.ALARM_ID, intent.getExtras().getInt(Constants.ALARM_ID));
        if(intent.getExtras().containsKey(Constants.SNOOZE_ALARM)){
            b.putString(Constants.SNOOZE_ALARM, intent.getExtras().getString(Constants.SNOOZE_ALARM));
        }
        i.putExtras(b);
        //this flag is needed to start an Activity from a BroadcastReceiver
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);


        //this method reads from the DB and sets the next alarm
        //I tried commenting this method so that no DB action is 
        //performed and still the bug happened
        setAlarm(context.getApplicationContext());
        //this method just logs data into a file that I have created to keep track of events 
        //since not always the device is connected with LogCat
        Utils.logToFile("Received Alarm, Intent(context, StopAlarm.class);");
    }

我是否需要设置任何其他标志?在某些情况下,startActivity(intent)如何表现不正确?

修改

<activity
    android:label="@string/app_name"
    android:name="package.activity.StopAlarm"
    android:windowSoftInputMode="stateAlwaysHidden" 
    android:screenOrientation="sensorPortrait">
</activity>

<receiver android:name="package.receivers.AlarmReceiver" />

2 个答案:

答案 0 :(得分:3)

我终于通过创建IntentService并从IntentService启动活动并将两个标志设置为Intent来解决问题。执行此操作后,我将从DB读取的代码放在从IntentService启动的活动中。我已经测试了近60倍的行为,并且在所有测试中,应用程序的行为都正确。我发布下面的代码。

    public class MyAlarmReceiver extends WakefulBroadcastReceiver {
        // The app's AlarmManager, which provides access to the system alarm services.
        private static AlarmManager alarmMgr;
        // The pending intent that is triggered when the alarm fires.
        private static PendingIntent alarmIntent;

        @Override
        public void onReceive(Context context, Intent intent) {
            Intent i = new Intent(context, AlarmIntentService.class);
            Bundle b = new Bundle();
            b.putInt(Constants.ALARM_ID, intent.getExtras().getInt(Constants.ALARM_ID));
            if(intent.getExtras().containsKey(Constants.SNOOZE_ALARM)){
                b.putString(Constants.SNOOZE_ALARM, intent.getExtras().getString(Constants.SNOOZE_ALARM));
            }
            i.putExtras(b);
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            startWakefulService(context, i);
        }

这是我需要实施的IntentService

    public class AlarmIntentService extends IntentService {
        public AlarmIntentService() { 
            super("AlarmIntentService"); 
        } 

        @Override 
        protected void onHandleIntent(Intent intent) {
            Intent i = new Intent(this, StopAlarm.class);
            Bundle b = new Bundle();
            b.putInt(Constants.ALARM_ID, intent.getExtras().getInt(Constants.ALARM_ID));
            if(intent.getExtras().containsKey(Constants.SNOOZE_ALARM)){
                b.putString(Constants.SNOOZE_ALARM, intent.getExtras().getString(Constants.SNOOZE_ALARM));
            }
            i.putExtras(b);
            //THESE ARE THE FLAGS NEEDED TO START THE ACTIVITY AND TO PREVENT THE BUG
            //(CLEAR_TASK is crucial for the bug and new task is needed to start activity from outside of an activity)
            i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK);

            startActivity(i);

            MyAlarmReceiver.completeWakefulIntent(intent);
        } 
    } 

这是IntentService启动的活动。在这里,我设置了下一个警报。

public class StopAlarm extends Activity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.stop_alarm);
        //this method reads from the DB and sets the next alarm
        MyAlarmReceiver.setAlarm(getApplicationContext());
        ...

答案 1 :(得分:1)

我有类似的问题。根据我的经验,问题是,startActivity(i)是异步的。因此在这种情况下,程序将同时调用onCreate(),onStart()等活动,但也调用QlokAlarmReceiver.completeWakefulIntent(intent)(无需等待活动关闭),这将释放wakeLock。因此,设备可以在执行onCreate()或onStart()上的活动时进入休眠状态。

鲁宾,我知道,我的答案与你的解决方案相矛盾,但我的日志清楚地表明了这样的事件顺序: - 调用startActivity - onCreate of the activity called - completeWakefulIntent(intent);在活动的onStart的日志之间调用

我的解决方法是在调用startActivity之前启动一个带有例如20秒超时的唤醒锁,然后在onCreate中启动另一个wakeLock,它将在onDestroy方法中释放。 我不确定我的解决方案是否符合最佳做法,但到​​目前为止我还没有找到更好的解决方案。