Android:共享数据并从第 3 方应用程序接收文本。为什么我的应用收不到新文本?

Android: Sharing Data and Receiving text from 3rd party app. Why doesn't my app receive new text?

总结

我正在尝试获取用户通过“共享”菜单发送的数据。在这种情况下,我将使用基本的 Android 网络浏览器来 select 文本,然后将其共享到我的应用程序。

问题

用户第一次分享文本时,我的应用程序按预期获取文本并通过 Log.d() 显示它——请参阅 下面代码中的 handleSendText() 方法。

但是,此后每次即使用户在网络浏览器中 select 编辑了新文本并与我的应用程序共享,我仍然会得到用户 select 编辑的原始文本(上一个价值)。

问题

您如何重置 Intent —— 或者不管它是什么 —— 以便我可以获得用户在第一次 selected 后的新文本?

详情

我的应用程序有一个 MainActivity 并且我遵循了 Google 文档: http://developer.android.com/training/sharing/receive.html

在我的 MainActivity

中使用如下代码
public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    Intent intent = getIntent();
    String action = intent.getAction();
    String type = intent.getType();

    if (Intent.ACTION_SEND.equals(action) && type != null) {
        if ("text/plain".equals(type)) {
            handleSendText(intent, "onCreate"); // Handle text being sent
        }
    }
}

@Override
public void onResume(){
    super.onResume();
    Intent intent = getIntent();
    String action = intent.getAction();
    String type = intent.getType();

    if (Intent.ACTION_SEND.equals(action) && type != null) {
        if ("text/plain".equals(type)) {
            handleSendText(intent, "onResume"); // Handle text being sent
        }
    }

}

void handleSendText(Intent intent, String callingMethodName) {
    String sharedText = intent.getStringExtra(Intent.EXTRA_TEXT);
    if (sharedText != null) {
    Log.d("MainActivity", "sharedText : " + sharedText + " called from : " + callingMethodName);
    }
}

}

我的 Androidactivity 的清单部分添加了如下过滤器:

<activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
            </intent-filter>
        </activity>

浏览屏幕和日志

注意:请注意,我已经在我的应用程序中实现了 onResume(),以确保我不仅在调用 onCreate() 时获得 Intent(仅在应用程序启动时出现一次)。

启动浏览器并抓取文本 "hurricane"。

选择要共享的应用(我们的测试应用)。

查看日志发现调用了onCreate()和onResume(),值为'hurricane'

再次返回浏览器以分享更多文本...

Select一个新词,大西洋,分享。

补充说明:当我们点击那个Share link 这次Android MenuChooser 没有显示,而是自动再次打开GrabText。我发现这种行为有些奇怪。

请注意,Intent 文本仍然具有飓风值。您可以看到 logcat.

中现在有两个新条目

尝试的变通解决方案

我发现我可以通过覆盖 onPause() 并在我的 [=238] 上调用 finish() 来完全破坏应用程序=](从而关闭整个应用程序)这似乎可行,但是否有其他方法可以重置该 Intent 或相关文本或其他内容?

您是否知道任何其他方法来确保检索到新数据? 感谢您的帮助。

更新 注意:我正在更新,因为没有很好的方法来显示已尝试的其他代码,但是,如果没有其他 SO 用户的输入,我不知道要尝试这个,CommonsWare.

我收到的第一个答案是我应该添加一个 @Override onNewIntent() 所以我将以下代码添加到我的 MainActivity:

 @Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        Log.d("MainActivity", "onNewIntent()...");
        String action = intent.getAction();
        String type = intent.getType();
        if (Intent.ACTION_SEND.equals(action) && type != null) {
            if ("text/plain".equals(type)) {
                handleSendText(intent, "onNewIntent"); // Handle text being sent
            }
        }

    }

添加该代码和 运行 并尝试复制和复制新单词后,我仍然在 logcat 中看到以下内容:

看起来甚至没有调用 onNewItent() 方法。

编辑 2

我更改了模拟器设置...开发人员选项...并关闭了 "Don't keep activities" 设置。它先前已打开(选中)。

之后,我 运行 包含 onNewIntent() 覆盖的应用程序,但现在它只显示 onCreate() 消失了(这是有道理的,因为 activity 仍在加载)但仍然没有显示 onNewIntent() 调用。 在此示例中,我捕获了单词 "remnants".

编辑 3

我构建了该应用程序并创建了一个 APK,并将其部署到我的 Samsung Galaxy Core Prime,但最终得到了相同的结果。 onNewIntent() 从未 被调用。

我刚刚在 Google 文档中查找了 onNewIntent,它指出:

onNewIntent(Intent intent) This is called for activities that set launchMode to "singleTop" in their package, or if a client used the FLAG_ACTIVITY_SINGLE_TOP flag when calling startActivity(Intent).

我还没有设置 singleTop 所以我现在试试。嗯....

编辑 4

我现在已经尝试了 singleTop 变体。我之前在模拟器上测试 API 15 (v4.0.4),所以我切换到 API 21 (v5.0) 看看是否有任何不同。

这是添加 singleTop 对我的 AndroidManifest.xml 所做的:

<activity android:name=".MainActivity" android:launchMode="singleTop">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
        <data android:mimeType="text/plain" />
    </intent-filter>
</activity>

请注意,我还将两个 intent-filter 节点合并为一个。

Selected 文本已更改

在 Android API 级别 21 中,每次我在浏览器中 selected 文本时,Intent 文本现在都不同。

onNewIntent 从未被调用

但是,永远不会调用 onNewIntent。我从来没有看到它火过。

每次显示的分享菜单

此外,现在(在 API 21)我每次 select 发短信时都会看到共享菜单。 然而,当我切换到浏览器时,我也看到了一件有趣的事情。您可以在列表中看到 Activity 的多个副本。什么?!

另请注意,我将 MainActivity 实现为 ListView(可滚动),因此即使没有 logcat(对于真实设备上的 运行)我也可以看到条目。这让其他事情变得明显:ListView 在每个新显示的 Activity 上被更新。但实际上,它应该是原始的 Activity 被附加到。

创建大量 GrabText 活动 是的,现在每次我 select 文本时它都会创建一个新的 GrabText Activity window。我想这可能是因为我设置了 singleTop,所以我删除了它,但即使在 API LEVEL 21.

上删除 singleTop 后它们仍然出现

现在我看到它起作用了——每次在 API 21 上提供不同的文本,我决定切换回 API Level 15 模拟器并尝试一下。

我会在 API 级别 15 上再次尝试一些事情后报告。

API 15 级:再次测试

我再次启动了我的另一个模拟器 运行 API 15 级和 运行 应用程序,即使设置了 singleTop,该值也永远不会更新。

您可以在 logcat 和更新的 ListView 中看到:

您还可以看到代码的行为完全不同,尽管我没有更改任何内容,因为它附加到 运行 Activity api 级别 15 的 ListView .

我已经写了一本书来讨论这个非常有据可查的事情。我希望这对某人有所帮助,希望 Google Android 开发人员看到并解释它。

如果您的 activity 已经存在,它将使用 onNewIntent() 而不是 onCreate() 来调用。 onNewIntent() 将传递给您需要用于消息的 Intent

尝试将 manifest.xml 中 activity 的 android:launchMode 更改为 单顶

如果 activity 已经启动,将在 onNewIntent() 方法

中接收新的意图

只有一个答案确实有效,但它可能会导致其他问题。

您只需决定在 Activity 进入 onPause() 时调用 finish()。

这是我实现的适用于所有 API 关卡的确切代码。

@Override
    public void onPause(){
        super.onPause();
        finish();
    }

消灭Activity

当您添加该代码时,每次您切换回您正在共享的应用程序(在我们的例子中是网络浏览器)时,onPause 将在您的 MainActivity 和 finish() 方法上触发将 Activity 设置为销毁。

此后每次显示的分享菜单

使用此解决方案,每次您 select 从您的共享应用程序(网络浏览器)发送文本时,都会显示“共享”菜单并将 GrabText 显示为选项之一(而不是自动强制将 GrabText 置于最前面再次)。

共享文本永远是新文本

由于 MainActivity 已完全销毁,因此必须再次完全加载 (onCreate()),因此它会收到发送的新 Intent 文本。

不是很好的解决方法

但这不是一个很好的解决方法,因为我相信您的应用程序中的对话框也会创建要调用的 onPause() 并且您的 Activity 将被破坏。显然,破坏你的 Activity onPause() 也不是很好,因为你开始以一种真正应该留给 OS 的方式来管理 "memory"。但是,在这种情况下,这似乎是解决问题的唯一方法。