2014-12-05 87 views
3

我有一個非常奇怪的錯誤發生在我的應用程序。我正在構建一個鬧鐘應用程序,我正在使用SQLite存儲鬧鐘數據和廣播接收器來管理鬧鐘管理器調用。WakefulBroadcastReceiver意圖不只在某些情況下啓動(奇怪)

在某些情況下,onReceive的代碼奇怪地不以相同的方式表現。我嘗試在接收器收到廣播時開始一個活動,將近90%的情況一切順利,我設法啓動活動,但在某些情況下,奇怪的是接收器執行指令「startActivity(i)」,但沒有任何反應。

這是真的很難重現的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" /> 
+0

請從您的Manifest發佈您的活動聲明代碼,以更好地瞭解問題。 – 2014-12-05 15:12:51

+0

剛剛添加了清單。該代碼在90%的案例中起作用,所以意圖開始我的活動,但奇怪的是在某些情況下它不會啓動它。 – Rubin 2014-12-05 16:25:11

+0

你的代碼看起來很好。我可以推薦的唯一更改是使用intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK),而不是intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)。此外,當它失敗的時間達到10%時,是否通過按主頁按鈕將活動置於後臺。 – 2014-12-05 19:13:28

回答

3

我終於通過創建IntentService並開始從IntentService活動和兩個標誌設置爲意圖解決的問題。完成此操作後,我將從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); 
     } 

這是我需要實現

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啓動該活動的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()); 
     ... 
+0

但Intent.FLAG_ACTIVITY_CLEAR_TASK摧毀我的應用程序業務內部邏輯(可能有多個警報活動)。該怎麼辦? – 2016-10-20 11:39:20

+0

P.S. :是否有必要: 意向i =新意圖(上下文,AlarmIntentService.class); i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); //必要? startWakefulService(context,i); – 2016-10-20 11:56:38

+0

這是你得到的,如果你刪除標誌。現在我檢查剛剛刪除Clear_Task時發生的情況 從AndroidMonitor中的崩潰日誌中引用「android.util.AndroidRuntimeException:從Activity上下文外部調用startActivity()需要FLAG_ACTIVITY_NEW_TASK標誌,這真的是你想要的嗎? – Rubin 2016-10-20 12:28:10

1

我有類似的問題。根據我的經驗,問題是,startActivity(i)是異步的。因此,在這種情況下,程序將同時調用onCreate(),onStart()等活動,但也會調用QlokAlarmReceiver.completeWakefulIntent(intent)(不等待活動被關閉),這將釋放wakeLock。因爲在執行活動onCreate()或onStart()時,設備可以進入睡眠狀態。

魯賓,我知道,我的回答是解決方案的一對矛盾,但我的日誌清楚地表明事件這樣的順序: - startActivity稱爲 - 活性的onCreate稱爲 - completeWakefulIntent(意向);從活動的onStart之間的日誌之間調用

我的解決方法是在調用startActivity之前啓動超時例如20秒的wakelock,然後在onCreate中啓動另一個wakeLock,它將在onDestroy方法中發佈。 我不確定我的解決方案是否符合最佳實踐,但到目前爲止還沒有找到更好的解決方案。

相關問題