У меня есть приложение с заставкой Activity Activity, за которой следует основное действие. Заставка запускает материал (базу данных и т.д.) Перед началом основной операции. Из этого основного действия пользователь может перейти к нескольким другим дочерним действиям и обратно. Некоторые дочерние действия запускаются с использованием startActivityForResult()
, другие - только startActivity()
.
Иерархия активности показана ниже.
| Child A (startActivityForResult)
| /
|--> Splash --> Main -- Child B (startActivityForResult)
| ^ \
| | Child C (startActivity)
| \
| This Activity is currently skipped if a Notification is started
| while the app is not running or in the background.
При нажатии кнопки Notification мне нужно выполнить следующее поведение :
- Состояние в Управлении должно поддерживаться, так как пользователь выбрал несколько рецептов для создания списка покупок. Если новая активность запущена, я считаю, что состояние будет потеряно.
- Если приложение находится в главной операции, принесите это на передний план и сообщите мне в коде, который я получил из Уведомления.
- Если приложение находится в дочернем режиме. Активность, начинающаяся с
startActivityForResult()
, мне нужно добавить данные в намерение, прежде чем возвращаться к основной активности, чтобы она могла правильно поймать результат. - Если приложение находится в дочернем режиме. Активность, начинающаяся с
startActivity()
, мне просто нужно вернуться, поскольку больше нечего делать (в настоящее время это работает). - Если приложение не находится в фоновом режиме или переднем плане (то есть оно не работает), я должен запустить Main Activity, а также знать, что я пришел из Notification, чтобы я мог настроить вещи, которые не настроены тем не менее, поскольку в этом случае функция Splash Activity пропускается в моей текущей настройке.
Я пробовал много различных предложений здесь, в SO и в других местах, но я не смог успешно получить описанное выше поведение. Я также пробовал читать документацию, но не стал намного мудрее, немного. Моя текущая ситуация для вышеуказанных случаев при нажатии на мое уведомление:
- Я прихожу в основную деятельность в
onNewIntent()
. Я не прихожу сюда, если приложение не работает (или в фоновом режиме). Это кажется ожидаемым и желаемым. - Я не могу понять, что я исхожу из уведомления в любом дочернем мероприятии, поэтому я не могу правильно называть
setResult()
в этих действиях. Как мне это сделать? - В настоящее время это работает, поскольку уведомление просто закрывает дочернюю активность, что нормально.
- Я могу получить намерение уведомления в
onCreate()
с помощьюgetIntent()
иIntent.getBooleanExtra()
с булевым набором в уведомлении. Поэтому я должен был бы заставить его работать, но я не уверен, что это лучший способ. Каков предпочтительный способ сделать это?
Текущий код
Создание уведомления:
Уведомление создается, когда HTTP-запрос внутри Сервиса возвращает некоторые данные.
NotificationCompat.Builder builder = new NotificationCompat.Builder(context)
.setSmallIcon(getNotificationIcon())
.setAutoCancel(true)
.setColor(ContextCompat.getColor(context, R.color.my_brown))
.setContentTitle(getNotificationTitle(newRecipeNames))
.setContentText(getContentText(newRecipeNames))
.setStyle(new NotificationCompat.BigTextStyle().bigText("foo"));
Intent notifyIntent = new Intent(context, MainActivity.class);
notifyIntent.setAction(Intent.ACTION_MAIN);
notifyIntent.addCategory(Intent.CATEGORY_LAUNCHER);
notifyIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
/* Add a thing to let MainActivity know that we came from a Notification. */
notifyIntent.putExtra("intent_bool", true);
PendingIntent notifyPendingIntent = PendingIntent.getActivity(context, 0, notifyIntent, PendingIntent.FLAG_UPDATE_CURRENT);
builder.setContentIntent(notifyPendingIntent);
NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(111, builder.build());
MainActivity.java:
@Override
protected void onCreate(Bundle savedInstanceState)
{
Intent intent = getIntent();
if (intent.getBooleanExtra("intent_bool", false))
{
// We arrive here if the app was not running, as described in point 4 above.
}
...
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
switch (requestCode)
{
case CHILD_A:
// Intent data is null here when starting from Notification. We will thus crash and burn if using it. Normally data has values when closing CHILD_A properly.
// This is bullet point 2 above.
break;
case CHILD_B:
// Same as CHILD_A
break;
}
...
}
@Override
protected void onNewIntent(Intent intent)
{
super.onNewIntent(intent);
boolean arrivedFromNotification = intent.getBooleanExtra("intent_bool", false);
// arrivedFromNotification is true, but onNewIntent is only called if the app is already running.
// This is bullet point 1 above.
// Do stuff with Intent.
...
}
Внутри дочернего элемента Действие началось с startActivityForResult()
:
@Override
protected void onNewIntent(Intent intent)
{
// This point is never reached when opening a Notification while in the child Activity.
super.onNewIntent(intent);
}
@Override
public void onBackPressed()
{
// This point is never reached when opening a Notification while in the child Activity.
Intent resultIntent = getResultIntent();
setResult(Activity.RESULT_OK, resultIntent);
// NOTE! super.onBackPressed() *must* be called after setResult().
super.onBackPressed();
this.finish();
}
private Intent getResultIntent()
{
int recipeCount = getRecipeCount();
Recipe recipe = getRecipe();
Intent recipeIntent = new Intent();
recipeIntent.putExtra(INTENT_RECIPE_COUNT, recipeCount);
recipeIntent.putExtra(INTENT_RECIPE, recipe);
return recipeIntent;
}
AndroidManifest.xml:
<application
android:allowBackup="true"
android:icon="@mipmap/my_launcher_icon"
android:label="@string/my_app_name"
android:theme="@style/MyTheme"
android:name="com.mycompany.myapp.MyApplication" >
<activity
android:name="com.mycompany.myapp.activities.SplashActivity"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.mycompany.myapp.activities.MainActivity"
android:label="@string/my_app_name"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan" >
</activity>
<activity
android:name="com.mycompany.myapp.activities.ChildActivityA"
android:label="@string/foo"
android:parentActivityName="com.mycompany.myapp.activities.MainActivity"
android:screenOrientation="portrait"
android:windowSoftInputMode="adjustPan" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mycompany.myapp.activities.MainActivity" >
</meta-data>
</activity>
<activity
android:name="com.mycompany.myapp.activities.ChildActivityB"
android:label="@string/foo"
android:parentActivityName="com.mycompany.myapp.activities.MainActivity"
android:screenOrientation="portrait" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.mycompany.myapp.activities.MainActivity" >
</meta-data>
</activity>
...
</manifest>