简体   繁体   中英

Launch a particular Fragment using Navigation component when tapped on Notification that is sent from WorkManager

I'm sending a daily notification to the user based on a condition from the Worker that is launched using BroadcastReceiver. From Worker I only have context for sending notification.

NotificationCompat.Builder(context, CHANNEL_ID).apply {
    setContentTitle(...)
    setContentText(...)
    setContentIntent(pendingIntent(context)) 
}.build()

How do I create PendingIntent for launching a particular fragment using Navigation component?

I tried this:

fun pendingIntent(context: Context): PendingIntent {
    val navController = NavController(context.applicationContext)
    navController.setGraph(R.navigation.your_navigation)
    return navController.createDeepLink()
        .setDestination(R.id.yourFragment)
        .createPendingIntent()
}

But I get following exceptions:

Caused by: java.lang.RuntimeException: Exception inflating package.name:navigation/your_navigation line 7
        at androidx.navigation.NavInflater.inflate(NavInflater.java:90)
        at androidx.navigation.NavController.setGraph(NavController.java:425)
        at androidx.navigation.NavController.setGraph(NavController.java:407)
        at 
        ......
        at package.name.Worker.doWork(Worker.kt:15)
        at androidx.work.Worker$1.run(Worker.java:85)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) 
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) 
        at java.lang.Thread.run(Thread.java:761) 
Caused by: java.lang.IllegalStateException: Could not find Navigator with name "fragment". You must call NavController.addNavigator() for each navigation type.
        at androidx.navigation.NavigatorProvider.getNavigator(NavigatorProvider.java:98)
        at androidx.navigation.NavInflater.inflate(NavInflater.java:100)
        at androidx.navigation.NavInflater.inflate(NavInflater.java:132)
        at androidx.navigation.NavInflater.inflate(NavInflater.java:81)
        at androidx.navigation.NavController.setGraph(NavController.java:425) 
        at androidx.navigation.NavController.setGraph(NavController.java:407) 
        at package.name.NotificationKt.pendingIntent(Notification.kt:57) 
        at package.name.buildNotificationFor(Notification.kt:50) 
        at package.name.showNotificationFor(Notification.kt:22) 
        at package.name.doWork(Worker.kt:15) 
        at androidx.work.Worker$1.run(Worker.java:85) 

As per the Create an explicit deep link documentation , you should be using the NavDeepLinkBuilder class:

fun pendingIntent(context: Context): PendingIntent {
    return NavDeepLinkBuilder(context)
       .setGraph(R.navigation.your_navigation)
       .setDestination(R.id.android)
       .createPendingIntent()
}

This answer is more suited for the question asked by @Alexa289 here but since the question was closed on the basis that this is a similar question and answer provided by @ianhanniballeke should suffice. I am compelled to write the answer here. The answer provided by @ianhanniballake is brillant but it only work for certain condition when dealing with onMessageReceived() of a class extending FirebaseMessagingService() . When the activity is in foreground, the service provide activity based context hence the code works fine, but when the activity is not in foreground, the class provide service based context, hence the pendingIntent created from NavDeepLinkBuilder works differently. So here goes my solution for the non-foreground cases. Firstly, create the pendingIntent through the usual way

fun pendingIntent(context: Context): PendingIntent {
    return NavDeepLinkBuilder(context)
       .setGraph(R.navigation.your_navigation)
       .setDestination(R.id.android)
       .createPendingIntent()
}

then you need to catch the pending intent through intent filter in the android manifest like this

        <intent-filter>
            <action android:name="*TheClassNameOfFragmentYourDestinationPointsTo*" />
            <category android:name="android.intent.category.DEFAULT"/>
        </intent-filter>

Then from the home fragment, you can grab the intent that start the activity like this

val intent = (activity as? AppCompatActivity)?.intent

From the intent you can extract the extras in the bundle then navigate to the fragment you wish to like this

findNavController().navigate(R.id.android)

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