Comment obtenir une activité d'hébergement à partir d'une vue?

193

J'ai un Activityavec 3 EditTexts et une vue personnalisée qui agit comme un clavier spécialisé pour ajouter des informations dans le EditTexts.

Actuellement, je passe le Activitydans la vue afin que je puisse obtenir le texte d'édition actuellement ciblé et mettre à jour le contenu à partir du clavier personnalisé.

Existe-t-il un moyen de référencer l'activité parent et d'obtenir le focus actuel EditTextsans passer l'activité dans la vue?

mAndroid
la source
7
La bonne réponse est par gomino.
djunod

Réponses:

310

Je viens de retirer ce code source du MediaRouter dans la bibliothèque de support officielle et jusqu'à présent, cela fonctionne 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
la source
15
tandis que? pourquoi alors?
Jakob Eriksson
11
C'est juste un moyen de remonter à travers tout le contexte de base, jusqu'à ce que l'activité soit trouvée, ou de quitter la boucle lorsque le contexte racine est trouvé. Parce que le contexte racine aura un baseContext nul, menant à la fin de la boucle.
Gomino
1
Très bien ! J'ai remplacé ((Activity) getContext ()) par getActivity () et cela fonctionne très bien .... Merci
Christian
comme on l'a dit, getContext () peut ne pas toujours représenter un objet Activity si votre View n'est pas appelé à partir d'un contexte Activity. Par exemple, cela ne fonctionne pas pour les vues personnalisées.
Tohid
@AbhinavSaxena Pourriez-vous nous donner un exemple où ce code échouerait? Même si la méthode elle-même renvoie null, elle ne devrait jamais y arriver.
Tiago
169

les méthodes suivantes peuvent vous aider

  1. Activity host = (Activity) view.getContext(); et
  2. view.isFocused()
dira
la source
35
N'oubliez pas que cela getContext()peut ne pas toujours renvoyer un objet Activity si votre vue n'est pas appelée à partir d'un contexte Activity. Assurez-vous de planifier cela à l'avance et de fournir une solution de secours appropriée.
Dzhuneyt
1
@WordPressDeveloper - Comment créer une vue sans activité? Vous voulez dire la vue à distance? Existe-t-il d'autres cas de vues créés en dehors d'une activité?
AlikElzin-kilaka
1
@kilaka Widgets, Fragments, RemoteViews, LayoutInflaters sont tous les cas où vous pouvez créer une vue qui n'est pas liée à une activité.
Dzhuneyt
4
@WordPressDeveloper - Lorsque vous créez une vue dans un fragment, son contexte est toujours l'activité. Les fragments ne peuvent résider que dans les activités.
AlikElzin-kilaka
25
C'est un casting assez dangereux à faire. Il y a de fortes chances (si vous utilisez appcompat) que le contexte que vous avez soit enveloppé, lancer quelque chose comme un ContextThemeWrapperto Activitylancera un ClassCastException. Vous auriez besoin d'un moyen de dérouler le contexte de base (qui devrait être une activité), ce qui en soi est dangereux car il existe une version native et v7 de ContextThemeWrapper.
alex
19

J'aime cette solution écrite en Kotlin

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

Utilisation en Viewclasse

context.getActivity()

Code décompilé:

public static final Activity getActivity(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
la source
2
merci, vraiment l'apprécier pour cette belle activité de scan sur kotlin
mochadwi
2
Vous pouvez aussi faire:tailrec fun Context?.getActivity(): Activity? = this as? Activity ?: (this as? ContextWrapper)?.baseContext?.getActivity()
Westy92
10

Je pris Gomino de réponse Modifiés pour l' adapter parfaitement à myUtils.java pour que je puisse l' utiliser où et quand j'ai besoin. J'espère que quelqu'un le trouvera utile :)

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;
    }
}
brownieFille
la source
Ce n'est pas la réponse efficace, car il y a des chances d'obtenir null comme renvoyé par cette fonction. Ma réponse est universellement applicable, bien que grâce à un travail acharné et à la compréhension: stackoverflow.com/a/51077569/787399
Abhinav Saxena
-1

Dans Android 7+, la vue n'a plus accès à l'activité englobante, elle view.getContext()ne peut donc plus être castée vers une activité.

Au lieu de cela, le code ci-dessous fonctionne sous Android 7+ et 6:

private static Activity getActivity(final View view) {
    return (Activity) view.findViewById(android.R.id.content).getContext();
}
Sebas LG
la source
6
"Dans Android 7+, la vue n'a plus accès à l'activité englobante, donc view.getContext () ne peut pas être castée en activité" Une référence?
Simple Fellow
@SimpleFellow comme mentionné dans d'autres commentaires, getContextretournera probablement un ContextThemeWrapperafin que la vue n'ait plus un accès direct à l'activité. Au lieu de cela, vous devez rechercher de manière récursive dans les contextes parents jusqu'à ce que vous trouviez l'activité parente ou utilisez la méthode que j'ai fournie dans cette réponse.
Sebas LG
-1

Propriété d'extension Kotlin pour que View récupère l'activité parent:

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
la source
Vous pouvez remplacer les deux ifpar whenet le isInstance()par !is ContextWrapperouis Activity
David Miguel
Selon @Gomino, le contexte racine aura un baseContext nul. Ainsi, votre implémentation peut lancer une ClassCastException dans ce cas
David Miguel
C'est une vieille solution. Mieux vaut utiliser la solution de @Vlad
Fedir Tsapana
-1

@Override public boolean shouldOverrideUrlLoading (vue WebView, requête WebResourceRequest) {if (request.getUrl (). GetHost (). StartsWith ("pay.google.com")) {Intent intent = new Intent (Intent.ACTION_VIEW, request.getUrl ()); view.getContext (). startActivity (intention); retourne vrai; } ... ...}

Tomcolins Cox Violet CHilton c
la source
1
Bonjour et bienvenue dans Stack Overflow. veuillez expliquer votre réponse plus que juste l'exemple de code; regardez d'autres réponses par exemple.
Itamar Mushkin le