单击带有附加功能的Android通知以初始化应用程序或更新数据:在以前的通知启动应用程序时未处理

时间:2018-07-30 10:31:06

标签: android android-notifications android-pendingintent

当收到聊天消息的推送消息时,我的应用程序会显示一条通知。当我单击该消息时,我想启动该应用程序(如果尚未启动),该应用程序应直接转发到特定的聊天屏幕(而不是主屏幕)。如果该应用程序已经存在于该屏幕中,它将更新显示的消息(实际上类似于WhatsApp)。

当前,除以下情况外,这在大多数情况下似乎都可以很好地工作:

  • 在应用关闭后单击聊天通知(该应用已正确启动,我希望它在聊天屏幕中启动)
  • 导航远离该屏幕
  • 收到新通知(即使这是来自其他人的聊天)
  • 点击此新通知
  • 根本不执行通知操作。该应用程序被带到前台,但没有其他反应。

请注意:无论我收到哪个通知,以及我往返聊天屏幕的频率如何,在最初以正常方式启动应用程序时(始终不能通过通知点击)正确地处理通知点击即可。

一些信息和代码:

我的应用程序有多个活动,其中最重要的活动是MainActivity,LoginActivity和InitializationActivity(后者是启动器,并选择应启动其他两个中的哪个)。这是相关的清单部分:

 <activity
     android:name=".activity.InitializationActivity"
     android:launchMode="singleTop">
     <intent-filter>
         <action android:name="android.intent.action.MAIN"/>
         <category android:name="android.intent.category.LAUNCHER"/>
     </intent-filter>
 </activity>
 <activity
     android:name=".activity.LoginActivity"
     android:launchMode="singleTop"/>
 <activity
     android:name=".activity.MainActivity"
     android:launchMode="singleTop"/>

初始化活动:

@Override
protected void onStart()
{
    super.onStart();
    decideStartUpMode();
}

@Override
protected void onNewIntent(Intent intent)
{
    // Just to be sure the intent from a notification is also saved through this method.
    // However, should not be required, because this activity is always destroyed before starting a new one.
    // Doesn't appear to be called in any case (decideStartUpMode is always called through onStart)
    super.onNewIntent(intent);
    setIntent(intent);
    decideStartUpMode();
}

private void decideStartUpMode()
{
    if (!isUserLoggedIn())
    {
        startLoginActivity();
    }
    else
    {
        // Starts some API calls to collect the required user info.
        // When the data is collected we callback to this class and start the MainActivity.
        startInitialization();
    }
}

...

private void startMainActivity()
{
    Intent intentActivityMain = new Intent(this, MainActivity.class);
    intentActivityMain.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

    // Collect (Pending)Intent from eg. notification - if present - and add this to the new activity
    Intent intentInitializationActivity = getIntent();
    intentActivityMain.setAction(intentInitializationActivity.getAction());
    intentActivityMain.setData(intentInitializationActivity.getData());
    Bundle extras = intentInitializationActivity.getExtras();
    if (extras != null)
    { // Extra's from notification
        intentActivityMain.putExtras(extras);
    }

    startActivity(intentActivityMain);
    finish();
}

MainActivity:

// INTENT_HANDLER will handle the actions from clicked push notifications

@Override
public void onCreate(@Nullable Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    INTENT_HANDLER.doIntentAction(getIntent(), this); // If activity is started through InitializationActivity
}

@Override
protected void onNewIntent(Intent newIntent)
{
    super.onNewIntent(newIntent);
    INTENT_HANDLER.doIntentAction(newIntent, this); // If activity was already active
}

最后创建具有启动器意图的通知:

public void showChatNotification(Context context, ChatNotification chatNotificationData)
{
    Bundle bundle = new Bundle();
    bundle.putSerializable(CHAT_NOTIFICATION_DATA, chatNotificationData);

    PendingIntent onNotificationClickIntent = getAppLauncherIntent(context, CHAT_NOTIFICATION, notificationId, extras);
    String channelId = // ... also create channel if not exists ...
    NotificationCompat.Builder notification = new NotificationCompat.Builder(getContext(), channelId);
    notification.setContentIntent(onNotificationClickIntent);
    notification.setAutoCancel(true);
    // ... Set other notification data: title, message, etc...
    context.getSystemService(Context.NOTIFICATION_SERVICE) 
           .notify(notificationId.id, notification.build());
}

private PendingIntent getAppLauncherIntent(Context context, String action, NotificationId notificationId, Bundle extras)
{
    Intent intent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
    intent.setAction(action);
    intent.putExtras(extras);
    return PendingIntent.getActivity(context, notificationId.id, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}

在通常情况下,始终通过InitialActivity(onCreate> onStart> startInitialization> startMainActivity)和MainActivity({{1 }}或onCreate)。但是,当我最初通过另一个通知(上述方法或onHandleIntent都未启动)启动应用程序后,单击通知时未调用InitializationActivity。

为什么在这种特定情况下会出错,而所有其他通知点击都得到正确处理?我的应用是否通过带有onHandleIntent的通知错误地初始化了(可能是由于使用了标志),因此它不再能够处理新的通知?

2 个答案:

答案 0 :(得分:1)

Notification启动应用程序时,如果该应用程序尚未运行,则Android会为该应用程序创建一个新任务,并将Activity启动到该任务中。 Android会记住用于启动任务的Intent
如果以后用户从Notification启动应用程序,则Android会将现有任务置于前台,因为用于启动应用程序的Intent与该任务最初的Intent相匹配用AND启动的Intent包含FLAG_ACTIVITY_NEW_TASK。这就是为什么在最初从Notification启动应用程序时看到这种奇怪行为的原因。

为防止此行为,您需要将FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS添加到Intent中使用的Notification中。这将防止Android记住用户使用此Intent启动了应用程序。

答案 1 :(得分:0)

我的问题通过将清单更改为

<activity
     android:name=".activity.InitializationActivity"
     android:launchMode="singleTop">

<activity
     android:name=".activity.InitializationActivity"
     android:launchMode="singleTask">

我不完全理解为什么(是的,我确实阅读了两个标志的文档),因此在注释中给出清晰的解释将非常有用。