- CompoundButton 源码分析
- LinearLayout 源码分析
- SearchView 源码解析
- LruCache 源码解析
- ViewDragHelper 源码解析
- BottomSheets 源码解析
- Media Player 源码分析
- NavigationView 源码解析
- Service 源码解析
- Binder 源码分析
- Android 应用 Preference 相关及源码浅析 SharePreferences 篇
- ScrollView 源码解析
- Handler 源码解析
- NestedScrollView 源码解析
- SQLiteOpenHelper/SQLiteDatabase/Cursor 源码解析
- Bundle 源码解析
- LocalBroadcastManager 源码解析
- Toast 源码解析
- TextInputLayout
- LayoutInflater 和 LayoutInflaterCompat 源码解析
- TextView 源码解析
- NestedScrolling 事件机制源码解析
- ViewGroup 源码解析
- StaticLayout 源码分析
- AtomicFile 源码解析
- AtomicFile 源码解析
- Spannable 源码分析
- Notification 之 Android 5.0 实现原理
- CoordinatorLayout 源码分析
- Scroller 源码解析
- SwipeRefreshLayout 源码分析
- FloatingActionButton 源码解析
- AsyncTask 源码分析
- TabLayout 源码解析
文章来源于网络收集而来,版权归原创者所有,如有侵权请及时联系!
5.3 onCreateView 和 createView 方法解析
onCreateView 有两个重载方法,最终调用的是 createView(String name, String prefix, AttributeSet attrs)
。
createView 主要做的操作有:
- 先通过 Filter,看是否过滤。
- 利用反射实例化 View 对象。
源码分析:
protected View onCreateView(View parent, String name, AttributeSet attrs) throws ClassNotFoundException { return onCreateView(name, attrs); } protected View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException { // 系统控件,前缀自动补上"android.view." return createView(name, "android.view.", attrs); } public final View createView(String name, String prefix, AttributeSet attrs) throws ClassNotFoundException, InflateException { // 通过以 View 的 name 为 key,查询构造函数的缓存 map 中时候已经有该 View 的构造函数。 Constructor<? extends View> constructor = sConstructorMap.get(name); Class<? extends View> clazz = null; try { Trace.traceBegin(Trace.TRACE_TAG_VIEW, name); // 构造函数在缓存的 map 中没有,则尝试去创建并添加。 if (constructor == null) { // 通过 类名去加载控件的字节码 clazz = mContext.getClassLoader().loadClass( prefix != null ? (prefix + name) : name).asSubclass(View.class); //如果有自定义的过滤器并且加载到字节码,则通过过滤器判断是否允许加载该 View。 if (mFilter != null && clazz != null) { boolean allowed = mFilter.onLoadClass(clazz); if (!allowed) { // 如果不允许则抛出异常。 failNotAllowed(name, prefix, attrs); } } // 得到构造函数 constructor = clazz.getConstructor(mConstructorSignature); constructor.setAccessible(true); // 缓存构造函数 sConstructorMap.put(name, constructor); } else { // setFilter() 可能会在类的构造函数被添加到 map 之后,所以获取到 map 中的构造函数后还需要判断是否过滤。 if (mFilter != null) { // 过滤的 map 中是否已经包含了此类名。 Boolean allowedState = mFilterMap.get(name); // 当前类名没有被放到过滤的缓存 map 中 if (allowedState == null) { // 重新加载类的字节码 clazz = mContext.getClassLoader().loadClass( prefix != null ? (prefix + name) : name).asSubclass(View.class); // 重新通过过滤器判断是否过滤。 boolean allowed = clazz != null && mFilter.onLoadClass(clazz); // 把过滤结果放到过滤的缓存 map 中。 mFilterMap.put(name, allowed); if (!allowed) { // 如果要过滤,则抛出异常。 failNotAllowed(name, prefix, attrs); } } else if (allowedState.equals(Boolean.FALSE)) { // 缓存构造函数的 map 中已经保存了当前要实例化的 View 的构造函数并且是要过滤的,抛出异常。 failNotAllowed(name, prefix, attrs); } } } // 实例化类的参数数组,0 是获取 LayoutInflater 传入的 Context,1 是 View 的属性 Object[] args = mConstructorArgs; args[1] = attrs; // 通过构造函数实例化 View(看到此行就知道,为什么自定义 View 或者 ViewGroup 的时候,如果在布局中使用的话,必须重写两个参数的构造函数了。) final View view = constructor.newInstance(args); // 如果当前 View 是 ViewStub,则把布局填充器设置给它。(因为 ViewStub 在此刻并不会填充期子 View,而是等需要的时候由用户手动触发。) if (view instanceof ViewStub) { // 把当前 LayoutInflater 的克隆传递给 ViewStub,让 ViewStub 实例化的时候用,因为 ViewStub 只是在需要的时候才会实例化 View。 final ViewStub viewStub = (ViewStub) view; viewStub.setLayoutInflater(cloneInContext((Context) args[0])); } return view; } catch (NoSuchMethodException e) { InflateException ie = new InflateException(attrs.getPositionDescription() + ": Error inflating class " + (prefix != null ? (prefix + name) : name)); ie.initCause(e); throw ie; } catch (ClassCastException e) { // If loaded class is not a View subclass InflateException ie = new InflateException(attrs.getPositionDescription() + ": Class is not a View " + (prefix != null ? (prefix + name) : name)); ie.initCause(e); throw ie; } catch (ClassNotFoundException e) { // If loadClass fails, we should propagate the exception. throw e; } catch (Exception e) { InflateException ie = new InflateException(attrs.getPositionDescription() + ": Error inflating class " + (clazz == null ? "<unknown>" : clazz.getName())); ie.initCause(e); throw ie; } finally { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } }
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论