Как передать данные от BroadcastReceiver до запускаемого действия? - PullRequest
9 голосов
/ 11 апреля 2010

У меня есть приложение Android, которое нужно время от времени просыпать в течение дня.

Чтобы сделать это, я использую AlarmManager для настройки PendingIntent и запускаю BroadcastReceiver. Затем этот BroadcastReceiver запускает действие, чтобы вывести пользовательский интерфейс на передний план.

Кажется, все вышеперечисленное работает, поскольку действие запускается правильно; но я бы хотел, чтобы BroadcastReceiver уведомил Activity, что она была запущена по тревоге (в отличие от запуска пользователем). Для этого я пытаюсь из метода onReceive () в BroadcastReceiver установить переменную в пакете дополнений намерения, таким образом:

    Intent i = new Intent(context, MyActivity.class);
    i.putExtra(wakeupKey, true);
    i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    context.startActivity(i);

В методе onResume () моего Activity я затем проверяю существование этой логической переменной:

protected void onResume() {
    super.onResume();

    String wakeupKey = "blah";      
    if (getIntent()!=null && getIntent().getExtras()!=null)
        Log.d("app", "onResume at " + System.currentTimeMillis() + ":" + getIntent().getExtras().getBoolean(wakeupKey));
    else
        Log.d("app", "onResume at " + System.currentTimeMillis() + ": null");
}

Вызов getIntent (). GetExtras () в onResume () всегда возвращает ноль - мне кажется, что я вообще не могу передать какие-либо дополнительные функции в этом комплекте.

Если я использую тот же метод для привязки дополнений к PendingIntent, который запускает BroadcastReceiver, тем не менее, дополнения проходят просто отлично.

Может ли кто-нибудь сказать мне, что отличает передачу пакета от BroadcastReceiver в Activity по сравнению с передачей пакета из Activity в BroadcastReceiver? Боюсь, что я могу сделать что-то совершенно очевидное неправильно ...

Ответы [ 5 ]

30 голосов
/ 28 июля 2011

Просто чтобы прояснить это (потому что я потратил много времени на выяснение того, как заставить это работать)

В классе обслуживания, который расширяется BroadcastReceiver. Введите следующий код в onReceive()

Intent intent2open = new Intent(context, YourActivity.class);
intent2open.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent2open.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
String name = "KEY";
String value = "String you want to pass";
intent2open.putExtra(name, value);
context.startActivity(intent2open);

FLAG_ACTIVITY_SINGLE_TOP гарантирует, что приложения не открываются, если они уже открыты. Это означает, что «старое» намерение, которое сначала открывало YourActivity, используется повторно, и оно НЕ будет содержать дополнительных значений. Вы должны поймать их в другом методе с именем onNewIntent() в YourActivity.

public class YourActivity extends Activity {
    private String memberFieldString;

    @Override
    public void onCreate(Bundle savedInstanceState) { 
         super.onCreate(savedInstanceState);
         setContentView(R.layout.main);

         // Code doing your thing...
    } // End of onCreate()

    @Override
    protected void onNewIntent(Intent intent) {
    Log.d("YourActivity", "onNewIntent is called!");

    memberFieldString = intent.getStringExtra("KEY");

    super.onNewIntent(intent);
} // End of onNewIntent(Intent intent)

    @Override
    protected void onResume() {
        if (memberFieldString != null) {
            if (opstartsIntent.getStringExtra(KEY) != null) {
               Log.d("YourActivity", "memberFieldString: "+ memberFieldString);
            } else {
               Log.d("YourActivity", "The intent that started YourActivity did not have an extra string value");
            }
        }
    } // End of onResume()

}  // End of YourActivity

Обратите внимание на два оператора if - onResume() не знает, вызывается ли он после OnCreate()->OnStart() OR onRestart()->onStart()
Пожалуйста, смотрите: http://www.anddev.org/images/android/activity_lifecycle.png

Он просто используется для проверки, запускается ли приложение пользователем (намерение без дополнений) ИЛИ BroadcastReceiver (намерение без дополнений).

5 голосов
/ 11 апреля 2010

Этот BroadcastReceiver затем запускает Деятельность по доведению пользовательского интерфейса до на переднем плане.

Это может быть суть вашей проблемы здесь. Попробуйте переопределить onNewIntent() и посмотреть, есть ли у передаваемого ему Intent дополнительная. Если это так, то это связано с тем, как вы настроили действие в манифесте (например, вы используете singleTop), и с тем фактом, что в данном конкретном случае действие уже существовало.

Вы можете также подумать о том, чтобы избавиться от i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); и посмотреть, имеет ли это значение значение.

В результате получается, что то, что вы делаете - добавление дополнительного в Intent для startActivity() - должно работать нормально. На самом деле, вы можете увидеть примеры этого здесь . Это говорит о том, что это что-то напуганное в деятельности (например, singleTop) или в том, как вы вызываете действие (например, FLAG_ACTIVITY_NEW_TASK).

EDIT:

Так как мои первые кадры не сработали, и с учетом вашего "любопытного" комментария выше ...

Это похоже на PendingIntent - с ними, если вы не предпримете шаги, вы не сможете обновлять дополнения.

По прихоти попробуйте добавить в свою активность в манифесте секунду <intent-filter>, просто по какой-то уникальной строке действия, и попробуйте запустить свою деятельность с получателя, используя это. Или просто добавьте некоторую строку действия в Intent, которую получатель использует для startActivity(), не вмешиваясь в манифест.

2 голосов
/ 11 апреля 2010

Вместо getIntent().getExtras().getBoolean(wakeupKey) более привычно писать getIntent().getBooleanExtra(wakeupKey, defaultValue). Я не уверен, связано ли это с вашей проблемой, но есть некоторые вещи, связанные с созданием пакета внутри getExtras (), в которых я не уверен, так что в любом случае это может стоить попробовать.

1 голос
/ 23 февраля 2011

Установить флаг Работает SingleTop (не смешивать с другими флагами)

Intent intent = new Intent(ContextManager.getContext(),OrderList.class);
intent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
Bundle bundle = new Bundle();       

bundle.putString("username",username);
bundle.putString("password",password);

intent.putExtras(bundle);
startActivityForResult(intent,0); 
0 голосов
/ 31 декабря 2012

Просто переопределите onNewIntent следующим образом, и переменная Bundle будет доступна в методе onresume:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
}
...