在XML布局里给View设置点击事件
给一个View设置监听点击事件是再普通不过的事情,比如 view.setOnClickListener(onClickListener); 另外一种做法是直接在XML布局里面指定View点击时候的回调方法,首先需要在Activity中编写用于回调的方法,比如 public void onClickView(View view){ // do something } 然后在XML设置View的 <View android:layout_width="match_parent" android:layout_height="match_parent" android:onClick="onClickView" /> 有的时候从XML布局里直接设定点击事件会比较方便(特别是在写DEMO项目的时候),这种做法平时用的人并不多,从使用方式上大致能猜出来,View应该是在运行的时候,使用反射的方式从Activity找到“onClickView”方法并调用,因为这种做法并没有用到任何接口。 接下来,我们可以从源码中分析出View是怎么触发回调方法的。
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; } } } 处理onClick属性的时候,先判断View的Context是否isRestricted,如果是就抛出一个IllegalStateException异常。看看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是用于判断当前的Context实例是否出于被限制的状态,按照官方的解释,处限制状态的Context,会忽略某些特点的功能,比如XML的某些属性,很明显,我们在研究的
不过isRestricted方法是Context中为数不多的有具体实现的方法(其余基本是抽象方法),这里直接返回false,而且这个方法只有在ContextWrapper和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中也只是代理调用mBase的isRestricted,而MockContext是写单元测试的时候才会用到,所以这里的isRestricted基本只会返回false,除非使用了自定义的ContextWrapper并重写了isRestricted。 /** * 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); } } 到这里就清楚了,当点击View的时候,DeclaredOnClickListener实例的“onClick”方法会被调用,接着会调用“resolveMethod”方法,使用反射的方式从View的Context中找一个叫“onClickView”方法,这个方法有一个View类型的参数,最后再使用反射调用该方法。要注意的是,“onClickView”方法必须是public类型的,不然反射调用时会抛出IllegalAccessException异常。 同时从源码也能看出,使用 此外,从DeclaredOnClickListener类的注释也能看出 最后,特别需要补充说明的是,使用 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |