¿Cómo obtener actividad de hosting desde una vista?

187

Tengo un Activitycon 3 EditTextsy una vista personalizada que actúa un teclado especializado para agregar información en el EditTexts.

Actualmente estoy pasando la Activityvista a la vista para poder obtener el texto de edición actualmente enfocado y actualizar los contenidos desde el teclado personalizado.

¿Hay alguna manera de hacer referencia a la actividad principal y obtener el foco actual EditTextsin pasar la actividad a la vista?

mAndroid
fuente
77
La respuesta correcta es por gomino.
djunod

Respuestas:

305

Acabo de extraer ese código fuente del MediaRouter en el biblioteca de soporte oficial y hasta ahora funciona bien:

private Activity getActivity() {
    Context context = getContext();
    while (context instanceof ContextWrapper) {
        if (context instanceof Activity) {
            return (Activity)context;
        }
        context = ((ContextWrapper)context).getBaseContext();
    }
    return null;
}
Gomino
fuente
13
¿mientras? porque mientras
Jakob Eriksson
9
Es solo una forma de burbujear a través de todo el contexto base, hasta que se encuentra la actividad, o salir del ciclo cuando se encuentra el contexto raíz. Porque el contexto raíz tendrá un contexto de base nulo, que conducirá al final del ciclo.
Gomino
1
Muy bien ! Reemplacé ((Activity) getContext ()) con getActivity () y funciona bien ... Gracias
Christian
como se ha dicho, getContext () puede no representar siempre un objeto Activity si su Vista no se llama desde un contexto Activity. Por ejemplo, no funciona para vistas personalizadas.
Tohid
@AbhinavSaxena ¿Podría darnos un ejemplo en el que este código podría fallar? Aunque el método en sí mismo devuelve nulo, nunca debería llegar allí.
Tiago el
168

los siguientes métodos pueden ayudarlo

  1. Activity host = (Activity) view.getContext(); y
  2. view.isFocused()
dira
fuente
35
Simplemente no olvide que getContext()puede que no siempre devuelva un objeto Actividad si su Vista no se llama desde un contexto Actividad. Asegúrese de planificar esto con anticipación y proporcionar una alternativa adecuada.
Dzhuneyt
1
@WordPressDeveloper - ¿Cómo se puede crear una vista sin una actividad? ¿Te refieres a la vista remota? ¿Hay otros casos de vistas que se crean fuera de una Actividad?
AlikElzin-kilaka
1
@kilaka Widgets, Fragments, RemoteViews, LayoutInflaters son todos los casos en los que puede crear una vista que no está vinculada a una Actividad.
Dzhuneyt
44
@WordPressDeveloper: cuando crea una vista en un fragmento, su contexto sigue siendo la actividad. Los fragmentos solo pueden residir en actividades.
AlikElzin-kilaka
24
Este es un elenco bastante peligroso para hacer. Existe una buena posibilidad (si está usando appcompat) de que el contexto que tiene esté envuelto, arrojando algo así como un ContextThemeWrapperto Activityarrojará un ClassCastException. Necesitaría una forma de desenvolver el contexto base (que debería ser una Actividad), que en sí mismo es peligroso ya que hay una versión nativa y v7 de ContextThemeWrapper.
alex
12

Me gusta esta solución escrita en Kotlin.

tailrec fun Context?.activity(): Activity? = when (this) {
    is Activity -> this
    else -> (this as? ContextWrapper)?.baseContext?.activity()
}

Uso en Viewclase

context.activity()

Código descompilado:

public static final Activity activity(Context context) {
    while (!(context instanceof Activity)) {
        if (!(context instanceof ContextWrapper)) {
            context = null;
        }
        ContextWrapper contextWrapper = (ContextWrapper) context;
        if (contextWrapper == null) {
            return null;
        }
        context = contextWrapper.getBaseContext();
        if (context == null) {
            return null;
        }
    }
    return (Activity) context;
}
Vlad
fuente
1
gracias, realmente lo aprecio por esta agradable actividad de escaneo en kotlin
mochadwi
8

Tomé Gomino 's respuesta y lo modificó para encajar perfectamente en myUtils.java para que pueda utilizarlo en cualquier lugar y siempre que necesito. Espero que alguien lo encuentre útil :)

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;
    }
}
browniegirl
fuente
Esta no es la respuesta efectiva, ya que hay posibilidades de obtener un valor nulo según lo devuelto por esta función. Mi respuesta es universalmente aplicable, aunque a través de un arduo trabajo y comprensión: stackoverflow.com/a/51077569/787399
Abhinav Saxena
-1

En Android 7+, la vista ya no tiene acceso a la actividad adjunta, por lo que view.getContext()ya no se puede transmitir a una Actividad.

En cambio, el siguiente código funciona en Android 7+ y 6:

private static Activity getActivity(final View view) {
    return (Activity) view.findViewById(android.R.id.content).getContext();
}
Sebas LG
fuente
66
"En Android 7+, la vista ya no tiene acceso a la actividad adjunta, por lo que view.getContext () no se puede transmitir a una Actividad" ¿ Alguna referencia?
Simple Fellow
@SimpleFellow, como se menciona en otros comentarios, getContextprobablemente devolverá un mensaje ContextThemeWrapperpara que la Vista ya no tenga acceso directo a la Actividad. En su lugar, debe buscar recursivamente los contextos principales hasta encontrar la Actividad principal o utilizar el método que proporcioné en esta respuesta.
Sebas LG
-1

Propiedad de extensión de Kotlin para Ver para recuperar la actividad principal:

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
    }
}
Fedir Tsapana
fuente
Podrías reemplazar los dos ifcon wheny isInstance()con !is ContextWrapperois Activity
David Miguel
Según @Gomino, el contexto raíz tendrá un contexto base nulo. Por lo tanto, su implementación puede arrojar una ClassCastException en este caso
David Miguel
Esta es una solución vieja. Mejor solución de uso por @Vlad
Fedir Tsapana
-1

@Override public boolean shouldOverrideUrlLoading (vista WebView, solicitud WebResourceRequest) {if (request.getUrl (). GetHost (). ComienzaWith ("pay.google.com")) {Intención de intención = nueva Intención (Intent.ACTION_VIEW, request.getUrl ()); view.getContext (). startActivity (intento); volver verdadero; } ... ...}

Tomcolins Cox Violet CHilton c
fuente
1
Hola, y bienvenido a Stack Overflow. explique su respuesta más que solo el ejemplo de código; mira otras respuestas por ejemplo.
Itamar Mushkin