Il est courant de configurer un événement de surveillance des clics pour une vue, telle que
view.setOnClickListener(onClickListener);
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 }
, 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" />
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.
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; } } }
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; }
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
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(); } }
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't search up the hierarchy, null out and fail. context = null; } } final int id = mHostView.getId(); final String idText = id == NO_ID ? "" : " with id '" + mHostView.getContext().getResources().getResourceEntryName(id) + "'"; 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); } }
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!