Search code examples
androidkotlinandroid-notifications

Creating a notification channel: required Context but found String


I'm trying to create a notification channel with some help from this tutorial (on creating notifications) and this tutorial (on creating alarms). I have this code:

private fun createNotificationChannel() {
    val importance = NotificationManager.IMPORTANCE_DEFAULT
    val channel = NotificationChannel(Notification.CATEGORY_REMINDER, "Reminder to Edit Trip", importance).apply {
        description = "Send half-hourly reminders to edit the details of a trip."
    }
    val notificationManager: NotificationManager = getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager //TODO
    notificationManager.createNotificationChannel(channel)
}

I don't know how to write the TODO line since I get the error "Required: Context, Found: String". The first tutorial wrote it as:

    NotificationManager notificationManager = getSystemService(NotificationManager.class)

which doesn't work because I get an error on NotificationManager saying "Classifier NotificationManager does not have a companion object, and thus must be initialised here", and the second tutorial wrote the line as:

private val alarmManager = context.getSystemService(AlarmManager::class.java)

which also doesn't work because of an error on context saying "None of the following functions can be called with the arguments supplied".

I found this SO question on the same issue, but the answer no longer works since context no longer has getSystemService(). I tried both

val notificationManager = Context.getSystemService(Context.NOTIFICATION_SERVICE) 

which gives the error "Unresolved reference: getSystemService()"

and

val notificationManager = ContextCompat.getSystemService(Context.NOTIFICATION_SERVICE);

which gives the error "Required: Context, Found: String".

So how can I write this now? I'm targeting API 30.


Solution

  • I figured it out (though don't really know the theory on why it works): we get the context via LocalContext.current, which then requires the function to be a composable. This would then require my calling function, onCreate() to be a composable, but that would clash with @SuppressLint and @OptIn, so I had to call the function from setContent(). Here's the entire code:

    class MainActivity : ComponentActivity() {
        @SuppressLint("UnusedMaterial3ScaffoldPaddingParameter")
        @OptIn(ExperimentalMaterial3Api::class)
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContent {
                WayToGoTheme ( content = {
                    Scaffold {
                        val context = LocalContext.current
                        val application = context.applicationContext as WayToGoApplication
                        val routeRepository = application.routeRepository
                        val waypointRepository = application.waypointRepository
                        val routeViewModel: RouteViewModel = remember { RouteViewModel(routeRepository) }
                        val waypointViewModel: WaypointViewModel = remember { WaypointViewModel(waypointRepository) }
                        val navController = rememberNavController()
    
                        CreateNotificationChannel()
    
                        NavGraph(navController = navController, waypointViewModel = waypointViewModel, routeViewModel = routeViewModel)
                    }
                })
            }
        }
    }
    
    
    @Composable
    private fun CreateNotificationChannel() {
        val ctx = LocalContext.current
    
        // Use LaunchedEffect to ensure the side effect happens only once
        LaunchedEffect(Unit) {
            val importance = NotificationManager.IMPORTANCE_DEFAULT
            val channel = NotificationChannel(Notification.CATEGORY_REMINDER, "Reminder to Edit Trip", importance).apply {
                description = "Send half-hourly reminders to edit the details of a trip."
            }
            val notificationManager = ctx.getSystemService(NotificationManager::class.java)
            notificationManager.createNotificationChannel(channel)
        }
    }