Partage de cas lors de la définition d'événements de clic pour la présentation Afficher dans XML

黄舟
Libérer: 2017-03-17 17:25:49
original
1571 Les gens l'ont consulté

Il est courant de configurer un événement de surveillance des clics pour une vue, telle que

    view.setOnClickListener(onClickListener);
Copier après la connexion

Une autre façon consiste à le spécifier directement dans le XML disposition Pour la méthode de rappel lorsque vous cliquez sur la vue, vous devez d'abord écrire la méthode de rappel dans l'activité, telle que

    public void onClickView(View view){
        // do something
    }
Copier après la connexion

, puis définir l'attribut android:onClick de la vue en XML

    <View
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:onClick="onClickView" />
Copier après la connexion

Parfois, il est plus pratique de définir des événements de clic directement à partir de la mise en page XML (en particulier lors de l'écriture de projets DEMO). Peu de gens utilisent généralement cette méthode. Vous pouvez le deviner à peu près. la méthode d'utilisation. La vue doit utiliser la réflexion pour trouver la méthode "onClickView" de l'activité et l'appeler lorsqu'elle est en cours d'exécution, car cette approche n'utilise aucune interface.

Ensuite, nous pouvons analyser comment View déclenche la méthode de rappel à partir du code source.

Partage de cas lors de la définition d'événements de clic pour la présentation Afficher dans XML
View a 5 méthodes de construction . La première est utilisée en interne. La deuxième méthode est généralement utilisée pour créer directement des instances de View dans le code Java. à partir de la mise en page XML appellera éventuellement la cinquième méthode.

public View(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        this(context);

        final TypedArray a = context.obtainStyledAttributes(
                attrs, com.android.internal.R.styleable.View, defStyleAttr, defStyleRes);
                
        for (int i = 0; i < N; i++) {
            int attr = a.getIndex(i);
            switch (attr) {
                ……
                // 处理onClick属性
                case R.styleable.View_onClick:
                    if (context.isRestricted()) {
                        throw new IllegalStateException("The android:onClick attribute cannot "
                                + "be used within a restricted context");
                    }

                    final String handlerName = a.getString(attr);
                    if (handlerName != null) {
                        // 给当前View实例设置一个DeclaredOnClickListener监听器
                        setOnClickListener(new DeclaredOnClickListener(this, handlerName));
                    }
                    break;
                }
        }
}
Copier après la connexion

Lors du traitement de l'attribut onClick, déterminez d'abord si le contexte de la vue est restreint, et si c'est le cas, lancez une IllegalStateException. Jetez un œil à la méthode isRestricted

    /**
     * Indicates whether this Context is restricted.
     *
     * @return {@code true} if this Context is restricted, {@code false} otherwise.
     *
     * @see #CONTEXT_RESTRICTED
     */
    public boolean isRestricted() {
        return false;
    }
Copier après la connexion

isRestricted est utilisé pour déterminer si l'instance de Context actuelle est dans un état restreint. Selon l'explication officielle, un Context dans un état restreint ignorera certaines fonctionnalités, telles que. as Certains attributs de XML, évidemment l'attribut android:onClick que nous examinons, sont également ignorés.

un contexte restreint peut désactiver des fonctionnalités spécifiques. Par exemple, une vue associée à un contexte restreint ignorerait des attributs XML particuliers.

Cependant, la méthode isRestricted en fait partie. les quelques-uns dans Context Il existe de nombreuses méthodes d'implémentation concrètes (les autres sont essentiellement des méthodes abstraites), ici renvoient directement false, et cette méthode n'est remplacée que dans ContextWrapper et MockContext
Partage de cas lors de la définition d'événements de clic pour la présentation Afficher dans XML

public class ContextWrapper extends Context {
    Context mBase;
    @Override
    public boolean isRestricted() {
        return mBase.isRestricted();
    }
}

public class MockContext extends Context {
    @Override
    public boolean isRestricted() {
        throw new UnsupportedOperationException();
    }
}
Copier après la connexion

ContextWrapper C'est aussi juste que l'agent appelle isRestricted de mBase, et MockContext n'est utilisé que lors de l'écriture de tests unitaires, donc isRestricted ici ne retournera fondamentalement que false, à moins qu'un ContextWrapper personnalisé ne soit utilisé et que isRestricted soit réécrit.
Revenez à View, puis final String handlerName = a.getString(attr); obtient en fait la android:onClick="onClickView" chaîne de "onClickView" dans , puis utilise l'instance de la vue actuelle et "onClickView" pour créer une instance DeclaredOnClickListener, et défini comme écouteur de clics de la vue actuelle.

/**
     * An implementation of OnClickListener that attempts to lazily load a
     * named click handling method from a parent or ancestor context.
     */
private static class DeclaredOnClickListener implements OnClickListener {
        private final View mHostView;
        private final String mMethodName;

        private Method mMethod;

        public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) {
            mHostView = hostView;
            mMethodName = methodName;
        }

        @Override
        public void onClick(@NonNull View v) {
            if (mMethod == null) {
                mMethod = resolveMethod(mHostView.getContext(), mMethodName);
            }

            try {
                mMethod.invoke(mHostView.getContext(), v);
            } catch (IllegalAccessException e) {
                throw new IllegalStateException(
                        "Could not execute non-public method for android:onClick", e);
            } catch (InvocationTargetException e) {
                throw new IllegalStateException(
                        "Could not execute method for android:onClick", e);
            }
        }

        @NonNull
        private Method resolveMethod(@Nullable Context context, @NonNull String name) {
            while (context != null) {
                try {
                    if (!context.isRestricted()) {
                        return context.getClass().getMethod(mMethodName, View.class);
                    }
                } catch (NoSuchMethodException e) {
                    // Failed to find method, keep searching up the hierarchy.
                }

                if (context instanceof ContextWrapper) {
                    context = ((ContextWrapper) context).getBaseContext();
                } else {
                    // Can&#39;t search up the hierarchy, null out and fail.
                    context = null;
                }
            }

            final int id = mHostView.getId();
            final String idText = id == NO_ID ? "" : " with id &#39;"
                    + mHostView.getContext().getResources().getResourceEntryName(id) + "&#39;";
            throw new IllegalStateException("Could not find method " + mMethodName
                    + "(View) in a parent or ancestor Context for android:onClick "
                    + "attribute defined on view " + mHostView.getClass() + idText);
        }
}
Copier après la connexion

C'est clair ici. Lorsque l'on clique sur View, la méthode "onClick" de l'instance DeclaredOnClickListener sera appelée, puis la méthode "resolveMethod" sera appelée, en utilisant la réflexion pour la trouver. le contexte de la vue. Une méthode est appelée "onClickView". Cette méthode a un paramètre de type View Enfin, la méthode est appelée en utilisant la réflexion. Il convient de noter que la méthode "onClickView" doit être de type public, sinon une IllegalAccessException sera levée lors de l'appel de réflexion.

En même temps, il ressort du code source que la façon de définir l'événement de clic à l'aide de android:onClick est de trouver la méthode de rappel à partir du contexte, donc si vous créez une vue dans le XML du Fragment, vous ne pouvez pas utiliser cette méthode. Lier la méthode de rappel dans Fragment, car Fragment lui-même n'est pas un contexte, le contexte de la vue ici est en fait FragmentActivity, ce qui signifie également que cette méthode peut rapidement rappeler Fragment à FragmentActivity.

De plus, la fonction de android:onClick peut également être vue à partir des commentaires de la classe DeclaredOnClickListener joue principalement le rôle de chargement paresseux Uniquement lorsque vous cliquez sur View. saura quelle méthode il est utilisé pour le rappel de clic.

Enfin, ce qu'il faut ajouter, c'est qu'utiliser android:onClick pour définir un événement de clic pour View signifie ajouter une méthode publique sans interface à l'activité. La tendance actuelle du développement Android est "N'écrivez pas de logique métier dans la classe Activity". Ceci est bénéfique pour la maintenance du projet et empêche l'explosion de l'activité, alors essayez de ne pas avoir de méthodes publiques sans interface et sans cycle de vie dans Activity. Par conséquent, utiliser android:onClick à la hâte peut "polluer" l'Activité.


Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal