android源码解析(1)--如何处理布局文件中添加的点击事件
来源:互联网 发布:朴槿惠犯了什么罪 知乎 编辑:程序博客网 时间:2024/05/01 10:12
我们都知道给view设置点击事件有三种方式:
第一种:View.setOnClickLintener(new OnClicklistener(...));
第二种:View.setOnClickListener(this); 然后让class去实现点击事件
第三种:xml文件中写onClick="XXXX";然后在activity中写方法XXX(View view)
其实前两种方法本质上没有什么区别,第二种就是有时候可以避免内存泄漏(不是一定可以避免,只有在activity中可以),今天我们来分析view源码是如何通过第三种xml方式设置点击事件的。
首先我们看看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); //此处省略n行无关代码 final int N = a.getIndexCount(); for (int i = 0; i < N; i++) { int attr = a.getIndex(i); switch (attr) { //此处省略N行无关代码 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) { setOnClickListener(new DeclaredOnClickListener(this, handlerName)); } break; //此处省略N行无关代码 } //此处省略N行无关代码 } //此处省略N行无关代码 }我们会发现,在构造器中会去读取onClick属性是否存在,如果存在则会读取到String类型的name,即handlerName,然后立即给我们设置了点击事件,原来系统帮我们设置了点击事件,那么又是如何传递到activity中的呢?为什么我们activity中要写handlerName名字的方法呢?我们就需要进入DeclaredOnClickListener()这个方法看看。很简单,代码如下:
/** * 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 mResolvedMethod; private Context mResolvedContext; public DeclaredOnClickListener(@NonNull View hostView, @NonNull String methodName) { mHostView = hostView; mMethodName = methodName; } @Override public void onClick(@NonNull View v) { if (mResolvedMethod == null) { resolveMethod(mHostView.getContext(), mMethodName); } try { mResolvedMethod.invoke(mResolvedContext, 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 void resolveMethod(@Nullable Context context, @NonNull String name) { while (context != null) { try { if (!context.isRestricted()) { final Method method = context.getClass().getMethod(mMethodName, View.class); if (method != null) { mResolvedMethod = method; mResolvedContext = context; return; } } } 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里面的一个静态内部类,实现了onClickListener接口,很简单,构造器传过来了点击的View和hanlderName,然后我们看onClick(View v)方法,会进入resolveMethod这个方法,进去看看吧。这个方法好像就是通过反射获取到了方法,然后通过context=null跳出while循环,如果找了半天发现没有找到这个方法,那就直接挂了!然后又回到onClick方法中执行了此方法,完了,就这么简单。。。但是,问题来了,那么是如何知道在activity中写的方法呢?假如我把此方法写到fragment中可不可以呢?答案是不可以的,这里我们会看到一个关键的context上下文,其实这个上下文就是activity,这就是为什么我们在activity中写此方法会被调用了。我们可以做个试验,假如说我在fragment的xml布局中添加点击事件,我把方法写到activity中,是否会执行呢?肯定会的,但是写到fragment中就不行。好了,很简单就这么多......
0 0
- android源码解析(1)--如何处理布局文件中添加的点击事件
- android中如果activity中应用fragementlayout布局文件,如何给其中的控件添加事件监听。
- Android : 如何在布局文件中添加自己的组件
- Android中如何在Fragment中添加点击事件切换新的Fragment
- Android中如何动态的添加布局
- Android 在XML文件中添加View点击事件的监听:OnClickListener
- android关于用.xml布局文件中对View添加OnClick事件无法响应的事情
- Android如何处理列表控件的item同时点击事件
- Android中RecyclerView添加item的点击事件
- Android中为RecyclerView添加item的点击事件
- Android开发中添加View控件的点击事件
- Android中Fragment点击事件的添加(及点击事件无响应的原因)
- 【Android】利用Java代码布局,按钮添加点击事件
- Android:ListView中嵌入GridView,处理点击事件的冲突
- Android PopupWindow中ListView 无法接受点击事件的处理
- 源码解析Android中的事件处理
- Android基础——界面布局简介、点击事件处理
- 源码解析Android中View的layout布局过程
- matlab imadjust 用 opencv改写
- 关于默认构造函数的一点琢磨--全局变量和局部变量
- 【高并发Java六】JDK并发包2
- python 斐波那契
- 异步获取数据Ajax,以及对获取的数据进行绑定(显示在页面上)
- android源码解析(1)--如何处理布局文件中添加的点击事件
- C#关闭子窗体更新父窗体(二)
- truncate 、delete与drop区别
- 抽象方法 接口 多重继承
- 69道有关Spring的问题和答案
- EMGU 三 打开摄像头
- SimpleGif,一款使用方法类似Glide但更省cpu、memory的Android ndk gif解码库,cmake方式,android studio项目
- JSONObject与JSONArray的使用
- STORM之ITridentSpout、FirstN(取Top N)实现、流合并和join