【问题标题】:Cannot call activity method from notification when app is NOT running应用未运行时无法从通知中调用活动方法
【发布时间】:2019-01-20 05:18:14
【问题描述】:

我有一个警报提醒,显示带有额外数据的通知。我想要做的是通过通知中的意图将额外数据发送到我的主要活动,然后在该活动中打开应用程序并调用特定方法(位置信息)。该方法将根据我传递的locationId 打开一个新活动。

当我的应用程序在后台运行时效果很好,但是当它被杀死时,即当应用程序完全关闭时,它会打开应用程序的主要活动,但不调用该方法。

我的通知代码用于有意发送数据:

Intent intent = new Intent(this, MainActivity.class);
intent.putExtra("fromNotification", true);
intent.putExtra("locationId", locationId);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP 
              | Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 111, intent, 
              PendingIntent.FLAG_UPDATE_CURRENT);

这就是我如何称呼我的方法:

@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    setIntent(intent);
    if (getIntent().hasExtra("fromNotification")) {
        String locationId = getIntent().getStringExtra("locationId");
        CallFetchLocationInfoFromMapsFragment(locationId);
    }
}

我也尝试在主要活动的 onCreate 末尾添加this,这应该是解决方案,但它什么也没做:

if (getIntent().hasExtra("fromNotification")) {
    String locationId = getIntent().getStringExtra("locationId");
    CallFetchLocationInfoFromMapsFragment(locationId);
}

我尝试了更多的解决方案(包括thisthisthisthisthisthisthis 等等),但无法成功工作。

Manifest(只是主要的活动部分):

<application
    android:name="com.weekendcoder.kemo.hotels.app.AppController"
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:screenOrientation="portrait"
        android:theme="@style/AppTheme.NoActionBar"
        android:launchMode="singleTask">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>
    ...
</application>

这是我理想工作流程的描述 - 如果我点击通知,它应该会打开我的 MainActivity,它有一个地图片段。在我的地图上加载所有内容后,我想从我的主要活动的地图开始一个新活动 - 我想使用从通知中收到的 id 打开 locationDetails 活动。由于关闭应用程序后调试停止,因此我无法查明问题,但我尝试添加以下内容:

if (getIntent().hasExtra("fromNotification")) 
{
    Toast.makeText(MainActivity.this, "Notification!", Toast.LENGTH_LONG).show();
}

在我的 onCreate 开始时,它确实显示了 toast。我不能在我的 onCreate 开始时使用这个条件,因为地图没有加载和设置,所以我在我的 onCreate 结束时添加了它。在这种情况下,它永远不会被调用。

我可以通过直接从通知中打开新活动来使其工作,但这不是我理想的解决方案。我希望能够在应用关闭时从通知中调用活动中的任何方法。

我也试过添加这个:

if (getIntent().hasExtra("fromNotification")) {
    String locationId = getIntent().getStringExtra("locationId ");
    CallFetchLocationInfoFromMapsFragment(locationId);
    Toast.makeText(MainActivity.this, "Notification id: " locationId, Toast.LENGTH_LONG).show();
}else{
    Toast.makeText(MainActivity.this, "No notification", Toast.LENGTH_LONG).show();
}

在我的 onCreate 结束时只是想看看我是否可以显示这个值,但我一直收到“无通知”toast。

当我在 onCreate 开始时设置相同的 if 条件时,它会崩溃:

08-14 18:06:03.319 18591-18591/com.weekendcoder.kemo.hotels D/SQLiteHandler: Fetching notification settings from sqlite db
08-14 18:06:03.329 18591-18591/com.weekendcoder.kemo.hotels W/Settings: Setting airplane_mode_on has moved from android.provider.Settings.System to android.provider.Settings.Global, returning read-only value.
08-14 18:06:03.384 18591-18591/com.weekendcoder.kemo.hotels D/AndroidRuntime: Shutting down VM
08-14 18:06:03.384 18591-18591/com.weekendcoder.kemo.hotels W/dalvikvm: threadid=1: thread exiting with uncaught exception (group=0x41cdc700)
08-14 18:06:03.389 18591-18591/com.weekendcoder.kemo.hotels E/AndroidRuntime: FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.weekendcoder.kemo.hotels/com.weekendcoder.kemo.hotels.MainActivity}: java.lang.NullPointerException
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2295)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2349)
    at android.app.ActivityThread.access$700(ActivityThread.java:159)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1316)
    at android.os.Handler.dispatchMessage(Handler.java:99)
    at android.os.Looper.loop(Looper.java:176)
    at android.app.ActivityThread.main(ActivityThread.java:5419)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:525)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862)
    at dalvik.system.NativeStart.main(Native Method)
 Caused by: java.lang.NullPointerException
    at com.weekendcoder.kemo.hotels.sliderfragments.MapsFragment.fetchlocationDetails(MapsFragment.java:545)
    at com.weekendcoder.kemo.hotels.MainActivity.CallFetchlocationDetailsFromMapsFragment(MainActivity.java:661)
    at com.weekendcoder.kemo.hotels.MainActivity.onCreate(MainActivity.java:324)
    at android.app.Activity.performCreate(Activity.java:5372)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1104)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2257)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2349) 
    at android.app.ActivityThread.access$700(ActivityThread.java:159) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1316) 
    at android.os.Handler.dispatchMessage(Handler.java:99) 
    at android.os.Looper.loop(Looper.java:176) 
    at android.app.ActivityThread.main(ActivityThread.java:5419) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:525) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1046) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:862) 
    at dalvik.system.NativeStart.main(Native Method) 

编辑:

有一个可行的解决方案,但我对此并不满意,希望找到更智能/更安全的解决方案。解决方案是在开头获取 id,然后添加:

if (locationId != null) {
    final Handler handler = new Handler();
    handler.postDelayed(new Runnable() {
        @Override
        public void run() {
            //Do something after 100ms
            CallFetchLocationInfoFromMapsFragment(locationId);
        }
    }, 5000);
}

这将使我的应用程序等待 5 秒,然后在所有其他方法执行后调用该方法。 这可行,但我不确定这是否是最好的方法,某些设备可能会更慢。最好找到一种方法来检查 onCreated 是否完全执行完毕,然后调用此方法。

【问题讨论】:

  • 您遇到了这个问题,因为一旦应用程序未运行并且用户单击通知,它将重定向到活动的创建方法,您无法调用 onNewIntent。您可以将数据存储在共享首选项上,然后在 onCreate 上检索它
  • @JineshChhichhiya 我知道在这种情况下(当应用程序未运行时)我不能使用 onNewIntent,但我应该能够在我的 onCreate 中添加该代码(方法调用),并且它应该在以下情况下工作应用已关闭。
  • 发布您的清单
  • 在不检查所有代码的情况下,您可以尝试以下方法之一:1) 立即发布到处理程序。这将在onCreate() 完成后运行。 2) 运行onResume() 中的代码或发布到onResume() 中的处理程序(无延迟)。
  • @DavidWasser 你真的很有帮助,你之前对类似问题的回答也很有帮助:)

标签: java android android-intent android-notifications android-pendingintent


【解决方案1】:

在 cmets(上)的讨论中,您表示您使用的是launchMode="singleTask"。这是一种特殊的启动模式,您的应用程序不需要。它通常产生的问题多于解决的问题。请删除特殊启动模式,看看是否有帮助。完成此操作后,在您的应用未运行时点击通知应该会启动该应用并创建一个 MainActivity 的新实例。

也有可能您无法在onCreate() 中做您想做的事情,因为您的Fragment 尚未设置。您可能只需要在onCreate() 中记住您想做什么(开始位置详细信息),但延迟实际执行直到onResume() 或您已经设置您的Fragments 或其他任何东西。

【讨论】:

    【解决方案2】:

    我认为你需要这个

    if (getIntent().hasExtra("fromNotification")) {
        String locationId = getIntent().getStringExtra("locationId");
        CallFetchLocationInfoFromMapsFragment(locationId);
    }
    

    在清单中为您的活动设置singleTask 启动模式

    <activity android:name=".YourActivity"
            android:launchMode="singleTask">
        ...
    </activity>
    

    【讨论】:

    • @nsdvd 我已将 if 条件放在我的 onCreate 末尾,但它不起作用。我将在今天晚些时候尝试它并让您知道它是否有效,但我想我可能已经尝试过 singleTask 模式。我今天再次测试后会告诉你。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多