如何在撰写中获得活动

ccd*_*ccd 8 android android-jetpack-compose

有没有办法在撰写功能中获取当前活动?

@Composable
fun CameraPreviewScreen() {
    val context = ContextAmbient.current
    if (ActivityCompat.checkSelfPermission(
            context,
            Manifest.permission.CAMERA
        ) != PackageManager.PERMISSION_GRANTED
    ) {
        ActivityCompat.requestPermissions(
            this, MainActivity.REQUIRED_PERMISSIONS, MainActivity.REQUEST_CODE_PERMISSIONS  // get activity for `this`
        )
        return
    }
}
Run Code Online (Sandbox Code Playgroud)

Jef*_*set 47

虽然之前的答案(即ContextWrapper-aware)确实是正确的,但我想提供一种更惯用的复制粘贴实现。

fun Context.getActivity(): ComponentActivity? = when (this) {
    is ComponentActivity -> this
    is ContextWrapper -> baseContext.getActivity()
    else -> null
}
Run Code Online (Sandbox Code Playgroud)

由于ContextWrappers 不可能相互缠绕很多次,因此递归在这里就可以了。

  • 只是最上面的樱桃,以对此答案的两个建议的形式,我真的很喜欢:1.用 `tailrec` 标记它 2. 它可能被写成 `val` 扩展: private tailrec fun Context.getActivity() :应用程序兼容性活动?= when (this) { is AppCompatActivity -> this is ContextWrapper -> baseContext.getActivity() else -> null } val Context.activity: AppCompatActivity? 获取()=获取活动() (2认同)
  • 我觉得真的很愚蠢,但这对我不起作用,因为我的活动是“Activity”而不是“AppCompatActivity”。因此,请确保您拥有正确的类型。 (2认同)

Abd*_*oui 45

您可以从转换上下文的可组合项中获取活动(我还没有发现上下文不是活动的情况)。然而,吉姆提到过,这样做并不是一个好的做法。

val activity = LocalContext.current as Activity
Run Code Online (Sandbox Code Playgroud)

就我个人而言,当我只是在玩一些需要活动的代码(权限是一个很好的例子)时,我会使用它,但是一旦我让它工作,我只需将其移动到活动并使用参数/回调。

编辑:正如评论中提到的,在生产代码中使用它可能很危险,因为它可能会崩溃,因为 current 是上下文包装器,我的建议主要用于测试代码。

  • 这可能会崩溃。在这种情况下,Context 不一定是 Activity,它可以是 ContextWrapper。 (8认同)
  • Compose 使用 setContent 中的 Activity(`this`) 初始化 ComposeView,从中获取上下文,并将其作为 LocalContext 提供。所以 `LocalContext.current as Activity` 是安全的。 (3认同)
  • 它不是。即使现在是这样,也没有什么可以阻止他们稍后将其更改为 ContextWrapper。Rajeev Shetty 演示了从 Context 获取 Activity 的正确方法 (3认同)

Raj*_*tty 24

获取上下文

val context = LocalContext.current
Run Code Online (Sandbox Code Playgroud)

然后使用上下文获取活动。创建一个扩展函数,并使用您的上下文调用此扩展函数,例如context.getActivity()

fun Context.getActivity(): AppCompatActivity? {
  var currentContext = this
  while (currentContext is ContextWrapper) {
       if (currentContext is AppCompatActivity) {
            return currentContext
       }
       currentContext = currentContext.baseContext
  }
  return null
}
Run Code Online (Sandbox Code Playgroud)


小智 13

internal fun Context.findActivity(): Activity {
    var context = this
    while (context is ContextWrapper) {
        if (context is Activity) return context
        context = context.baseContext
    }
    throw IllegalStateException("Permissions should be called in the context of an Activity")
}
Run Code Online (Sandbox Code Playgroud)
  • 它在可组合函数中使用,如下所示:

@Composable
fun composableFunc(){
    
    val context = LocalContext.current
    val activity = context.findActivity()

}

Run Code Online (Sandbox Code Playgroud)


Ji *_*bin 10

您可以通过Context创建.ActivityLocalActivity

val LocalActivity = staticCompositionLocalOf<ComponentActivity> {
    noLocalProvidedFor("LocalActivity")
}

private fun noLocalProvidedFor(name: String): Nothing {
    error("CompositionLocal $name not present")
}
Run Code Online (Sandbox Code Playgroud)

用法:

CompositionLocalProvider(LocalActivity provides this) {
   val activity = LocalActivity.current
   // your content
} 
Run Code Online (Sandbox Code Playgroud)

  • @JayBobzin 抱歉回复晚了。Compose 正在跟踪“setContent”中使用的活动的生命周期。如果 Activity 被销毁,Compose 会从 Composable 和“CompositionLocal”中删除所有数据。 (2认同)

小智 5

此扩展函数允许您指定想要获取的活动:

inline fun <reified Activity : ComponentActivity> Context.getActivity(): Activity? {
    return when (this) {
        is Activity -> this
        else -> {
            var context = this
            while (context is ContextWrapper) {
                context = context.baseContext
                if (context is Activity) return context
            }
            null
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

例子:

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent { HomeScreen() }
    }
}

@Composable
fun HomeScreen() {
    val activity = LocalContext.current.getActivity<MainActivity>()
}
Run Code Online (Sandbox Code Playgroud)


小智 1

从可组合函数中获取活动被认为是一种不好的做法,因为您的可组合项不应与应用程序的其余部分紧密耦合。除此之外,紧密耦合会阻止您对可组合项进行单元测试,并且通常会使重用变得更加困难。

查看您的代码,您似乎正在从可组合项中请求权限。同样,这不是您想要在可组合项中执行的操作,因为可组合函数可以像每帧一样频繁地运行,这意味着您将在每帧中继续调用该函数。

相反,请在活动中设置相机权限,并(通过参数)传递可组合项渲染像素所需的任何信息。

  • 感谢您的建议,但这并不能回答问题! (10认同)