简体   繁体   中英

Cannot call activity method from notification when app is NOT running

I have an alarm reminder that shows notification with extra data. What I want to do is send that extra data via intent from my notification to my main activity, and then open the app and call a specific method (location info) in that activity. That method will open a new activity, based on the locationId I have passed.

It works great when my app is running in the background , but when it is killed, ie when the app is completely closed, it opens the app's main activity, but does not call the method.

My notification code used to send data with intent:

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);

And this is how I call my mehtod:

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

I have also tried adding this at the end of my main activity's onCreate, and this should have been the solution, but it did nothing:

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

I tried a lot more solutions (including this , this , this , this , this , this , this , and many more), but couldn't make it work.

Manifest (just the main activity part):

<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>

Here is the description of my ideal workflow - if I click on the notification it should open my MainActivity, that has a maps fragment. After everything is loaded on my map, I would want to start a new activity from my main activity's map - I would like to open locationDetails activity using the id I received from the notification. Since the debugging stops as soon as I close the app I couldn't pinpoint the issue, but I have tried adding this:

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

at the beginning of my onCreate and it did display the toast. I can't use this condition on the beginning of my onCreate since the map is not loaded and set up, so I added it at the end of my onCreate. In this case it is never called.

I could make it work by opening that new activity directly from the notifications, but that is not my ideal solution. I would like to be able to call any method in activity from notification when the app is closed.

I have also tried adding this:

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();
}

at the end of my onCreate just to see if I can get this value to display, but i keep getting "No notification" toast.

When I put the same if condition at the start of my onCreate it crashes:

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) 

EDIT:

There is a possible solution that works , but I am not happy with it and would like to find something smarter/safer. The solution would be to get the id at the beginning and then add this:

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

That would allow my app to wait for 5 seconds and then call the method after all the other methods executed. This works , but I am not sure that it is the best way to go on with this, some devices might be slower. It would probably be better to find a way to check if onCreated completely finished executing and then call this method.

I think you need this

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

together with setting the singleTask launch mode for your activity in manifest

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

During a discussion in comments (above) you indicated that you were using launchMode="singleTask" . This is a special launch mode and should not be necessary for you app. It usually creates more problems than it solves. Please remove the special launch mode and see if that helps. Once you've done that, tapping the notification when your app is not running should launch the app and create a new instance of MainActivity .

It is also likely that you can't do what you want to do in onCreate() because your Fragment is not set up yet. You might need to just remember what you want to do (start location details) in onCreate() but delay actually doing it until onResume() or ater you've setup your Fragment s or whatever.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM