Android 自定义View、ViewGroup(一)之工作原理
2014-09-13 17:49
281 查看
学习Android自定义View,通常需要用到LayoutInflater这个类,先来简单的介绍一下LayoutInflater这个类的简单的用法。
下面我们来分析一下上面的流程
1.我们找到Activity.java的源码,看一下setContentView这个方法
3.那么mWindow是什么呢?我们在Activity.java中attach方法中找到一行代码
至此,整个Activity加载View的原理就说完了。
下载Demo请猛戳
1.两种获取LayoutInflater的方法
LayoutInflater layoutInflater = LayoutInflater.from(context); LayoutInflater layoutInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
2.LayoutInflater的工作原理
采用XmlPullParser 解析layout文件 创建view实例,最后调用viewGroup.addView(view, params);3.activity中的setContentView方法内幕
如果我们在activity_main中定义根布局为LinearLayout,父布局是一个FrameLayout,而这个FrameLayout就是由系统自动帮我们添加上的,其id就是content。这就是为什么Activity中有setContentView(),而不是setView()了举一个简单的例子:
1.在activity_main.xml中写一个布局文件如下<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="horizontal" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/hello_view" > </TextView> </LinearLayout>2.在MainActivity中设置布局
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE); // View contentView = layoutInflater.inflate(R.layout.activity_main, null); // setContentView(contentView); setContentView(R.layout.activity_main); } }我们用sdk/tools下自带的hierarchyviewer.bat工具可以清楚的看到整个布局情况。
下面我们来分析一下上面的流程
1.我们找到Activity.java的源码,看一下setContentView这个方法
public void setContentView(int layoutResID) { getWindow().setContentView(layoutResID); }2.可以看出其实调用的是getWindow这个方法返回的对象的setContentView方法,那么getWindow方法得到的是什么呢?
public Window getWindow() { return mWindow; }
3.那么mWindow是什么呢?我们在Activity.java中attach方法中找到一行代码
mWindow = PolicyManager.makeNewWindow(this);4.我们去PolicyManager中看一下makeNewWindow方法
private static final IPolicy sPolicy; public static Window makeNewWindow(Context context) { return sPolicy.makeNewWindow(context); }5.最终我们发现,原来是这个IPolicy这个接口调用makeNewWindow方法产生出的一个PhonwWindow实例(Window的实现类),然后调用它的setContentView方法
@Override public void setContentView(int layoutResID) { if (mContentParent == null) { installDecor(); } else { mContentParent.removeAllViews(); } mLayoutInflater.inflate(layoutResID, mContentParent); final Callback cb = getCallback(); if (cb != null) { cb.onContentChanged(); } }6.PhonwWindow的setContentView方法也是通过LayoutInflater的inflate方法去解析xml文件,转换成View对象,然后通过VIewGroup的addView方法完成,具体代码如下
public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) { synchronized (mConstructorArgs) { final AttributeSet attrs = Xml.asAttributeSet(parser); Context lastContext = (Context)mConstructorArgs[0]; mConstructorArgs[0] = mContext; View result = root; try { // Look for the root node. int type; while ((type = parser.next()) != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) { // Empty } if (TAG_MERGE.equals(name)) { if (root == null || !attachToRoot) { throw new InflateException("<merge /> can be used only with a valid " + "ViewGroup root and attachToRoot=true"); } //此方法内部解析XmlPullParser解析资源文件,调用Viewgroup的addView方法添加View到父View中 rInflate(parser, root, attrs); } else { // Temp is the root view that was found in the xml View temp = createViewFromTag(name, attrs); ViewGroup.LayoutParams params = null; if (root != null) { if (DEBUG) { System.out.println("Creating params from root: " + root); } // Create layout params that match root, if supplied params = root.generateLayoutParams(attrs); if (!attachToRoot) { // Set the layout params for temp if we are not // attaching. (If we are, we use addView, below) temp.setLayoutParams(params); } } // We are supposed to attach all the views we found (int temp) // to root. Do that now. if (root != null && attachToRoot) {
//如果root不为null,调用ViewGroup的addView方法将解析出的View添加到根view中 root.addView(temp, params); } } } catch (XmlPullParserException e) { InflateException ex = new InflateException(e.getMessage()); ex.initCause(e); throw ex; } catch (IOException e) { InflateException ex = new InflateException( parser.getPositionDescription() + ": " + e.getMessage()); ex.initCause(e); throw ex; } finally { // Don't retain static reference on context. mConstructorArgs[0] = lastContext; mConstructorArgs[1] = null; } return result; } }我们看一下rInflate方法吧
private void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs) throws XmlPullParserException, IOException { final int depth = parser.getDepth(); int type; while (((type = parser.next()) != XmlPullParser.END_TAG || parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) { if (type != XmlPullParser.START_TAG) { continue; } final String name = parser.getName(); if (TAG_REQUEST_FOCUS.equals(name)) { parseRequestFocus(parser, parent); } else if (TAG_INCLUDE.equals(name)) { if (parser.getDepth() == 0) { throw new InflateException("<include /> cannot be the root element"); } parseInclude(parser, parent, attrs); } else if (TAG_MERGE.equals(name)) { throw new InflateException("<merge /> must be the root element"); } else { final View view = createViewFromTag(name, attrs); final ViewGroup viewGroup = (ViewGroup) parent; final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs); rInflate(parser, view, attrs); viewGroup.addView(view, params); } } parent.onFinishInflate(); }
至此,整个Activity加载View的原理就说完了。
下载Demo请猛戳
相关文章推荐
- android之自定义ViewGroup
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- Android中自定义ViewGroup
- android之自定义ViewGroup和自动换行的布局的实现
- 在Android中,可以自定义类,继承ViewGroup等容器类,以实现自己需要的布局显示。
- (转)android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu
- android之自定义ViewGroup和自动换行的布局的实现
- android之自定义ViewGroup和自动换行的布局的实现
- Android开发教程:自定义ViewGroup方法总结
- android:自定义viewgroup,并实现滚动条和换行。
- Android中自定义ViewGroup
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu
- Android自定义ViewGroup自动换行实现滑动任意布局及事件处理效果
- android之自定义ViewGroup和自动换行的布局的实现
- android:自定义viewgroup,并实现滚动条和换行
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu
- Android学习:自定义ViewGroup方法总结
- android 自定义ViewGroup和对view进行切图动画实现滑动菜单SlidingMenu[转]
- Android 学习之--自定义ViewGroup