【问题标题】:How to get hosting Activity from a view?如何从视图中获取托管活动?
【发布时间】:2012-01-06 18:40:41
【问题描述】:

我有一个 Activity 和 3 个 EditTexts 和一个自定义视图,它充当专用键盘以将信息添加到 EditTexts。

目前我将Activity 传递到视图中,以便我可以获取当前聚焦的编辑文本并从自定义键盘更新内容。

有没有一种方法可以引用父活动并获得当前关注的EditText 而无需将活动传递到视图中?

【问题讨论】:

  • 正确答案是gomino。

标签: android android-activity android-edittext android-view


【解决方案1】:

我刚刚从 official support library 的 MediaRouter 中提取了该源代码,到目前为止它运行良好:

private Activity getActivity() {
    Context context = getContext();
    while (context instanceof ContextWrapper) {
        if (context instanceof Activity) {
            return (Activity)context;
        }
        context = ((ContextWrapper)context).getBaseContext();
    }
    return null;
}

【讨论】:

  • 同时?为什么?
  • 这只是一种在所有基本上下文中冒泡的方法,直到找到活动,或者在找到根上下文时退出循环。因为根上下文会有一个空的baseContext,导致循环结束。
  • 非常好!我用 getActivity() 替换了 ((Activity) getContext()) ,它工作正常......谢谢
  • 如前所述,如果您的 View 不是从 Activity 上下文调用的,则 getContext() 可能并不总是代表 Activity 对象。例如。它不适用于自定义视图。
  • @AbhinavSaxena 你能给我们举一个这个代码会失败的例子吗?即使方法本身返回 null,它也不应该到达那里。
【解决方案2】:

以下方法可能对您有所帮助

  1. Activity host = (Activity) view.getContext();和
  2. view.isFocused()

【讨论】:

  • 请不要忘记,如果您的 View 不是从 Activity 上下文调用的,getContext() 可能并不总是返回 Activity 对象。请务必提前计划并提供适当的后备方案。
  • @WordPressDeveloper - 如何在没有活动的情况下创建视图?你是说远程视图?是否还有其他在 Activity 之外创建视图的情况?
  • @kilaka Widgets、Fragments、RemoteViews、LayoutInflaters 都是您可以创建不绑定到 Activity 的视图的情况。
  • @WordPressDeveloper - 当您在片段中创建视图时,它的上下文仍然是活动。片段只能驻留在活动中。
  • 这是一个非常危险的演员阵容。很有可能(如果您正在使用 appcompat)您所获得的上下文已被包装,将类似 ContextThemeWrapper 的内容转换为 Activity 将抛出 ClassCastException。您需要一种方法来解开基本上下文(应该是一个 Activity),这本身就是危险的,因为有一个原生和 v7 版本的 ContextThemeWrapper
【解决方案3】:

更新

tailrec fun Context.getActivity(): Activity? = this as? Activity
    ?: (this as? ContextWrapper)?.baseContext?.getActivity()

感谢@Westy92

用法:

context.getActivity()

【讨论】:

  • 谢谢,非常感谢在 kotlin 上进行的这个不错的扫描活动
  • 你也可以这样做:tailrec fun Context?.getActivity(): Activity? = this as? Activity ?: (this as? ContextWrapper)?.baseContext?.getActivity()
【解决方案4】:

我采用了Gominoanswer 并对其进行了修改以完全适合myUtils.java,因此我可以随时随地使用它。希望有人觉得它有帮助:)

abstract class myUtils {
    public static Activity getActivity(View view) {
        Context context = view.getContext();
        while (context instanceof ContextWrapper) {
            if (context instanceof Activity) {
                return (Activity)context;
            }
            context = ((ContextWrapper)context).getBaseContext();
        }
        return null;
    }
}

【讨论】:

  • 这不是有效的答案,因为有机会从这个函数返回 null。我的回答是普遍适用的,尽管通过一些努力和理解:stackoverflow.com/a/51077569/787399
【解决方案5】:

请注意,如果您知道您的视图在 Fragment 内,您可以这样做:

FragmentManager.findFragment(this).getActivity();

从你的onAttachedToWindowonDraw 调用它,你不能更早调用它(例如onFinishInflate),否则你会得到一个例外。

如果您不确定您的视图是否在 Fragment 内,请参阅其他答案,例如Gomino,只是想把它扔在那里。

【讨论】:

    【解决方案6】:

    用于 View 检索父活动的 Kotlin 扩展属性:

    val View.activity: Activity?
    get() {
        var ctx = context
        while (true) {
            if (!ContextWrapper::class.java.isInstance(ctx)) {
                return null
            }
            if (Activity::class.java.isInstance(ctx)) {
                return ctx as Activity
            }
            ctx = (ctx as ContextWrapper).baseContext
        }
    }
    

    【讨论】:

    • 您可以将两个if 替换为when,将isInstance() 替换为!is ContextWrapperis Activity
    • 根据@Gomino,根上下文将有一个空的baseContext。因此,在这种情况下,您的实现可能会抛出 ClassCastException
    • 这是旧的解决方案。更好地使用@Vlad 的解决方案
    【解决方案7】:

    在 Android 7+ 中,视图无法再访问封闭的 Activity,因此无法再将 view.getContext() 强制转换为 Activity。

    相反,以下代码适用于 Android 7+ 和 6:

    private static Activity getActivity(final View view) {
        return (Activity) view.findViewById(android.R.id.content).getContext();
    }
    

    【讨论】:

    • “在 Android 7+ 中,视图无法再访问封闭的 Activity,因此无法将 view.getContext() 强制转换为 Activity” 有什么参考吗?
    • @SimpleFellow 正如其他 cmets 中提到的那样,getContext 可能会返回一个 ContextThemeWrapper,因此 View 不再可以直接访问 Activity。相反,您必须递归搜索父上下文,直到找到父 Activity 或使用我在此答案中提供的方法。
    【解决方案8】:

    @覆盖 public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { if(request.getUrl().getHost().startsWith("pay.google.com")) { Intent intent = new Intent(Intent.ACTION_VIEW, request.getUrl()); view.getContext().startActivity(intent); 返回真; } ... ... }

    【讨论】:

    • 嗨,欢迎来到 Stack Overflow。请解释您的答案,而不仅仅是代码示例;例如,看看其他答案。
    猜你喜欢
    • 1970-01-01
    • 2019-10-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-28
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多