226

I am trying to show a Toast message when I click on the item, but how do I get the context to pass the Toast class?

fun createListItem(itemIndex: Int) {
    Padding(left = 8.dp, right = 8.dp, top = 8.dp, bottom = 8.dp) {
        FlexRow(crossAxisAlignment = CrossAxisAlignment.Center) {
            expanded(1.0f) {
                Text("Item $itemIndex")
            }
            inflexible {
                Button(
                    "Button $itemIndex",
                    style = ContainedButtonStyle(),
                    onClick = {
                        Toast.makeText(
                            this@MainActivity,
                            "Item name $itemIndex",
                            Toast.LENGTH_SHORT
                        ).show()
                    })
            }
        }
    }
}
2
  • 1
    You might want to explain exactly what your problem was. I have used Toast in onClick handlers in Compose without a problem. If you were getting a compile error, please provide the complete details of the error. If you were getting a runtime error, please edit your question and post the stack trace. Commented Nov 7, 2019 at 12:04
  • 1
    FYI: while the answers below are valid, the compose team now recommends using Snackbar over Toast in Compose: kotlinlang.slack.com/archives/CJLTWPH7S/…. Commented Apr 19, 2021 at 18:57

13 Answers 13

409

Update March 2021: The previous answer has been deprecated. You should now use:

val context = LocalContext.current

Previous answer for reference:

You can access to context with define ambientContext.

Example:

val context = ContextAmbient.current
Sign up to request clarification or add additional context in comments.

7 Comments

compose is declarative & as a tree, so if you have complex trees and you need some state that could not provided from root component, you can use ambient or memo
Is there any doc that explains the use of this unaryPlus operator? I can't find anything solid to understand what it is and how to use it @Raka
When I add val context = +ambient(ContextAmbient) to Clickable then get java.lang.IllegalStateException: Composition requires an active composition context
please show your code (by gist.github.com) @AlexZezekalo
@RakaAdiNugroho I found out that I used a wrong place for getting context: firstly I wrote <code>val context = +ambient(ContextAmbient)<code> inside Clickable and it was the reason of that exception. Then I put this line out of the Clickable to the head of the function and everything became Ok. My fault.
|
97

ContextAmbient and AmbientContext has been deprecated.

You can replace them with LocalContext

Example:

val context = LocalContext.current

3 Comments

How can I use this val context = LocalContext.current as a global variable in my Activity?
@gauravkumar I think the most you can do is declaring it as the first line in setContent method because it only works inside composable function. If you need a context outside setContent, just use this.
Android changes faster than the speed of light.😁. I have never used ContextAmbient and AmbientContext in my life.
42

ContextAmbient.current is deprecated as of alpha-09.

AmbientContext.current is deprecated. I think as of alpha-11.

LocalContext.current is how you get the context in a composable now.

Comments

37

ContextAmbient and AmbientContext is deprecated

Update

Now Jetpack way to do this has been updated. It's now:

val context = LocalContext.current

2 Comments

What about Application context?
@IgorGanapolsky Once you have the local context, context.getApplicationContext()
36

The way to do this has been updated. It's now:

val context = LocalContext.current

LocalContext docs

Comments

33

LocalContext.current is the right approach. But the problem is you can't use LocalContext.current inside a @Composable function.

You need to create separate function to use Context:

@Composable
fun DoneButton() {
    val context = LocalContext.current
    Button(onClick = { showToast(context, "Button clicked")}) {
        Text(text = "Done")
    }
}

fun showToast(context: Context, msg: String) {
    Toast.makeText(context, msg, Toast.LENGTH_LONG).show()
}

1 Comment

This answer is somewhat contradictory. You definitely can use LocalContext.current inside a @Composable, it's just that you can't use it from inside the lambda argument scope.
14

ContextAmbient.current has been deprecated, use val context = LocalContext.current instead.

Comments

10

Some useful if you need get context as Activity from last Android Studio template:

val view = LocalView.current
(view.context as Activity).<activity method>

Better solution

fun Context.getActivity(): Activity? = when (this) {
    is Activity -> this
    is ContextWrapper -> baseContext.getActivity()
    else -> null
}

val activity = LocalContext.current.getActivity()

2 Comments

It is not safe as the context may not be an activity.
@EmadRazavi Agree, I updated my answer
6

For getting context in jetpack compose:

val context = ContextAmbient.current

Working on 0.1.0-dev14

How to use it in TOAST:

@Composable
fun cardViewImplementer(item: Int) {
   val context = ContextAmbient.current
   Card(
     shape = RoundedCornerShape(10.dp),
     modifier = Modifier.padding(10.dp)
   ) {
     Box(
        modifier = Modifier
            .fillMaxWidth()
            .drawShadow(5.dp)
            .clickable(onClick = {
                Toast.makeText(context, "Clicked $item", Toast.LENGTH_SHORT).show()
            }), children = {

        })
}

For accessing the Resource:

Text("Read this string: "+context.getString(R.string.name))

1 Comment

What does the unary plus mean in this context? (pun intended)
5

Issues with compose_version = '1.0.0-alpha12' ? AmbientContext is now LocalContext

Comments

2

You can use the LocalUriHandler:

val handler = LocalUriHandler.currenthandler 

Button( 
    onClick = { handler.openUri("https://www.stackoverflow.com") } 
) {    
     Text("Open") 
} 

Comments

1

In Jetpack Compose, you can get the Context using:

val context = LocalContext.current

It’s the easiest and most Compose-friendly way to do things like showing a Toast.

So if you want to show a Toast when clicking a button, your code should look like this:

@Composable
fun CreateListItem(itemIndex: Int) {
    val context = LocalContext.current

    Row(modifier = Modifier.padding(8.dp)) {
        Text("Item $itemIndex", modifier = Modifier.weight(1f))
        Button(onClick = {
            Toast.makeText(context, "Item name $itemIndex", Toast.LENGTH_SHORT).show()
        }) {
            Text("Button $itemIndex")
        }
    }
}

Other (less common) ways:

  • Pass context as a parameter from your Activity or ViewModel.

  • Use LocalView.current.context if you’re already working with views.

Just stick with LocalContext.current in most cases it works great!

Comments

0

Modify your createListItem function to accept a Context parameter:

fun createListItem(itemIndex: Int, context: Context) {
    Padding(left = 8.dp, right = 8.dp, top = 8.dp, bottom = 8.dp) {
        FlexRow(crossAxisAlignment = CrossAxisAlignment.Center) {
            expanded(1.0f) {
                Text("Item $itemIndex")
            }
            inflexible {
                Button(
                    "Button $itemIndex",
                    style = ContainedButtonStyle(),
                    onClick = {
                        Toast.makeText(
                            context,
                            "Item name $itemIndex",
                            Toast.LENGTH_SHORT
                        ).show()
                    }
                )
            }
        }
    }
}

Then call createListItem like this from an activity or composable that has access to context:

createListItem(itemIndex = 0, context = this) // inside Activity

// or from Compose
val context = LocalContext.current
createListItem(itemIndex = 0, context = context)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.