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?


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;
}

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()

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;
}

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;
    }
}

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();
}

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
    }
}

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; } ... ...}


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.