Java 启动新应用程序实例时,如何将数据传递给已经运行的应用程序实例

Java 启动新应用程序实例时,如何将数据传递给已经运行的应用程序实例,java,android,firebase,android-activity,Java,Android,Firebase,Android Activity,我的应用程序体系结构包括启动屏幕作为启动程序活动。启动应用程序后,启动屏幕被破坏。所以,为了防止由于启动器活动被破坏而重新启动应用程序,我在启动屏幕的onCreate方法中添加了以下内容: if (!isTaskRoot()) { finish(); return; } 所以,若已经运行的实例在那个里,并且显示了正在运行的实例,那个么新实例将自行完成。到目前为止还不错。 然而,新的应用程序实例并不总是从启动器启动。我已将Firebase消息设置为从服务器接收推送消息。推送消息包含一些附

我的应用程序体系结构包括启动屏幕作为启动程序活动。启动应用程序后,启动屏幕被破坏。所以,为了防止由于启动器活动被破坏而重新启动应用程序,我在启动屏幕的onCreate方法中添加了以下内容:

if (!isTaskRoot())
{
  finish();
  return;
}
所以,若已经运行的实例在那个里,并且显示了正在运行的实例,那个么新实例将自行完成。到目前为止还不错。 然而,新的应用程序实例并不总是从启动器启动。我已将Firebase消息设置为从服务器接收推送消息。推送消息包含一些附加数据,可以通过以下方式进行访问:

String messageId = getIntent().getStringExtra("id_message");
单击推送消息通知后启动新应用程序实例时。如果应用程序已经在运行,我需要在推送通知后显示它,单击“它工作”,然后处理消息_id(已运行的应用程序实例新实例应自行完成)。但我不知道如何将消息_id传递给已经运行的实例,以便能够在不重新启动整个应用程序的情况下处理它并显示消息详细信息


你知道吗?

首先在清单文件中的活动标记中添加启动模式,如

<activity
android:name="your_activity_name"
android:launchMode="singleTop" /> 
当您单击通知并开始任何活动时

如果您的活动不在那里,则将开始新的活动。
如果该活动已打开,则会调用其onNewIntentIntent意图,您将收到在此intent参数中发送的数据。

当应用程序中从firebase接收推送时,将由MyFirebaseMessagingService处理。在那里,您需要创建一个挂起的意图,即当用户点击通知时需要打开的活动

Intent resultIntent = new Intent(context, ActivityToOpen.class);

    TaskStackBuilder stackBuilder = TaskStackBuilder.create(context);
    stackBuilder.addNextIntentWithParentStack(resultIntent);
    PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(0, 
  PendingIntent.FLAG_UPDATE_CURRENT);
一旦用户单击通知,他们将被转移到活动ActivityToOpen

 Intent upIntent = 
 NavUtils.getParentActivityIntent(ActivityToOpenOnBackPress.this);
        if (NavUtils.shouldUpRecreateTask(CurrentActivityName.this, 
  upIntent)) 
       {

            TaskStackBuilder.create(CurrentActivityName.this)
                    .addNextIntentWithParentStack(upIntent)
                    .startActivities();
        } else {
            NavUtils.navigateUpTo(CurrentActivityName.this, upIntent);
        }
将此代码放在onBackPressed函数或工具栏导航click listener中。因此,当用户按下back按钮时,将创建一个人工堆栈,其余部分由android处理

在androidmanifest.xml中,通过添加以下代码为每个活动分配一个父活动
android:parentActivityName=.parentActivityName

您可以使用中间活动来选择要启动的活动

首先,创建启动活动:

对于空布局:

您需要在启动屏幕活动中设置标志

第三,将LaunchActivity设置为AndroidManifest.xml中的启动器,并将其设置为hidden和singleTask:

最后,您需要在启动splash活动后设置标志:

public class SplashScreenActivity extends AppCompatActivity {
  ...
  @Override 
  protected void onCreate(Bundle savedInstanceState) {
    ...

    BaseApp baseApp = (BaseApp) this.getApplication();
    baseApp.setHasGoToMain(true);
  }
}

现在,您可以发送意图并在主活动的onNewIntent内处理它。

我几乎遇到了同样的问题。我的应用程序从launcher或intent启动。添加splashscreen活动后,如果应用程序位于后台,则intent将从应用程序启动第二个实例

我将android:launchMode=singleTask添加到清单中的两个活动中,现在它像以前一样工作。一次只能有一个应用程序实例


对我来说没有任何意义,但只要它起作用,我不在乎…

这不是一个解决方案。发射器活动是飞溅活动。当应用程序运行时,SplashActivity已被销毁。所以它总是会启动新的SplashActivity,这将导致应用程序重新启动并从头开始运行,即使在按下Home按钮后应用程序已经在运行,isTaskRoot是为了避免这种情况,并立即关闭不需要的第二个实例。当应用程序未在后台运行时,启动从PushSplash启动后打开的第二个活动,而不是启动splash活动,它应该显示splash。因此,fcm中的单击操作需要指向飞溅活动。除了isTaskRoot之外,没有其他方法可以确定应用程序是否已在运行。主要问题是,如果应用程序位于后台,则我的应用程序在MyFirebaseMessagingService中未接收任何内容。相反,通知单击会导致启动新的应用程序实例这就是Firebase中通知有效负载的设计方式。然后,我可以通过getIntent.getStringExtra从新实例获取messageID`仅当应用程序位于前台时,才会调用onMessageReceived。而且,因为喷溅活动被破坏了。。。其余的你都知道。当你从服务器发送fcm时,我假设你在有效负载中添加了一个单击操作键,该键指定了当手机接收到有效负载时将处理该有效负载的活动?是的。它指向飞溅。否则,在应用程序尚未运行的情况下,会出现延迟,并且不会显示飞溅-在这种情况下,它应该正常启动,显示飞溅,然后向用户询问一些操作,最后显示已处理的消息详细信息如果您的启动屏幕不包含任何动画,则您可以遵循本指南,该指南将基本上为您的应用程序应用主题,这样您就不必重定向到启动屏幕活动,相反,您可以直接从通知单击链接到required活动,启动屏幕将自动显示
因为这是一个主题,所以我很高兴出现。如果您无法使用该解决方案,我建议您从启动屏幕启动所需的活动,并调用finishAffinity清除堆栈。这与我的解决方案完全相同。但是,您错了,SplashActivity是常规活动,不会自动显示。样式仅用于代替SplashActivity布局,但仍然需要调用SplashActivity,然后才能完成。Splash activity i sandroid.intent.category.LAUNCHER,需要直接调用。dea很有趣,绝对值得一试。我的情况有点复杂,顺序是:启动->登录如果没有登录,登录时停止提示密码->主要活动这与我面临的情况相同。我正在登录活动中处理登录,但启动屏幕尚未关闭。登录成功后,启动屏幕会被通知并关闭,然后从启动屏幕启动主活动。在我的例子中,启动屏幕会自动完成并启动LoginActivity。否则,在LoginActivity上按back将导致再次显示飞溅。物流活动必须位于StackOHH的顶部。。如果用户在登录时按back press,我总是关闭整个应用程序。你是说覆盖back press?然后关闭应用程序。我觉得这不是优雅的方式。事实上,我找不到任何指导方针,如何正确地、非常正确地、优雅地完成所有这些工作。没有任何肮脏的黑客如果你的飞溅被摧毁,飞溅活动就不存在,除非你的意图直接启动已经存在的活动,否则它将不起作用
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:visibility="gone">

</LinearLayout>
public class BaseApp extends Application {
  private boolean hasGoToMain = false;

  public boolean isHasGoToMain() {
    return hasGoToMain;
  }

  public void setHasGoToMain(boolean hasGoToMain) {
    this.hasGoToMain = hasGoToMain;
  }
}
<activity
    android:name=".LaunchActivity"
    android:screenOrientation="portrait"
    android:configChanges="orientation"
    android:launchMode="singleTask"
    android:theme="@android:style/Theme.NoDisplay"
    android:windowSoftInputMode="stateHidden">
  <intent-filter>
    <action android:name="android.intent.action.MAIN"/>
    <category android:name="android.intent.category.LAUNCHER"/>
  </intent-filter>
</activity>
<activity
    android:name=".SplashScreenActivity"
    android:launchMode="singleTask"
    android:configChanges="screenSize|orientation|screenLayout">

</activity>

<activity
    android:name=".MainActivity"
    android:launchMode="singleTask"
    android:label="@string/app_name"
    android:theme="@style/AppThemeMain.NoActionBar">
public class SplashScreenActivity extends AppCompatActivity {
  ...
  @Override 
  protected void onCreate(Bundle savedInstanceState) {
    ...

    BaseApp baseApp = (BaseApp) this.getApplication();
    baseApp.setHasGoToMain(true);
  }
}