Inflater英文意思是膨胀,在Android中应该是扩展的意思吧。
LayoutInflater的作用类似于 findViewById(),不同点是LayoutInflater是用来找layout文件夹下的xml布局文件,并且实例化!而 findViewById()是找具体某一个xml下的具体 widget控件(如:Button,TextView等)。
(0)她可以有很多地方可以使用,如BaseAdapter的getView中,自定义Dialog中取得view中的组件widget等等。
它的用法有2种:
传入的Name | 返回的对象 | 说明 |
WINDOW_SERVICE | WindowManager | 管理打开的窗口程序 |
LAYOUT_INFLATER_SERVICE | LayoutInflater | 取得xml里定义的view |
ACTIVITY_SERVICE | ActivityManager | 管理应用程序的系统状态 |
POWER_SERVICE | PowerManger | 电源的服务 |
ALARM_SERVICE | AlarmManager | 闹钟的服务 |
NOTIFICATION_SERVICE | NotificationManager | 状态栏的服务 |
KEYGUARD_SERVICE | KeyguardManager | 键盘锁的服务 |
LOCATION_SERVICE | LocationManager | 位置的服务,如GPS |
SEARCH_SERVICE | SearchManager | 搜索的服务 |
VEBRATOR_SERVICE | Vebrator | 手机震动的服务 |
CONNECTIVITY_SERVICE | Connectivity | 网络连接的服务 |
WIFI_SERVICE | WifiManager | Wi-Fi服务 |
TELEPHONY_SERVICE | TeleponyManager | 电话服务 |
Android中,为了载入某个布局文件,可以利用LayoutInflator类中的inflator方法,得到View实例。
值得注意的是,除了通常使用的inflator(int resource)这个重载,LayoutInflator也支持通过XmlPullParser来获取外部资源,如inflate(XmlPullParser parser, ViewGroup root),而之前我在没有查阅官方Reference时仅凭借对其他项目源码的实例阅读,就断定不能简单地通过android自身类库来调用外部布局文件,真可谓坐井观天。
AndroidDraw是界面生成工具Droiddraw的子项目,负责Layout Resource XML在客户端的解析生效,实现了类似于LayoutInflator的功能。它使用了辅助栈来还原UI树,并通过XmlPullParser的事件来解析整个XML。源码详见这里。
Android源码可以通过SDK Manager下载得到,在android-sdk\sources\android-APILevel\文件夹中。为了了解LayoutInflater的实现,自然寻找目录下LayoutInflater.java文件。
在LayoutInflator中,我没有按照method调用的顺序去阅读,而是下意识匆忙寻找onCreateView,该方法是Factory类的方法,但是在Android源码中并不存在Factory类!原来,Factory是接口- -
需要注意两个方法:
/** * Recursive method used to descend down the xml hierarchy and instantiate views, instantiate their children, and then call onFinishInflate(). */ void rInflate(XmlPullParser parser, View parent, final AttributeSet attrs, boolean finishInflate) throws XmlPullParserException, IOException /** * Low-level function for instantiating a view by name. This attempts to instantiate a view class of the given <var>name</var> found in this * LayoutInflater's ClassLoader. */
public final View createView(String name, String prefix, AttributeSet attrs) throws ClassNotFoundException, InflateException
注释很详细,rInflate递归地处理XML事件,并调用createView来生成具体的View,如Button等。createView中出现两个局部变量:
Constructor<? extends View> constructor = sConstructorMap.get(name); Class<? extends View> clazz = null;
问号是什么?Constructor关键字又是什么?在去年求职过程中,我才对Java泛型乃至STL有了一定的了解,更不用说Reflection。
Android官方实现与AndroidDraw作者实现区别就在于,Android源码采用了Reflection,避免了过多的条件嵌套:
clazz = mContext.getClassLoader().loadClass( prefix != null ? (prefix + name) : name).asSubclass(View.class); ... constructor = clazz.getConstructor(mConstructorSignature); return constructor.newInstance(args);
出于好奇,还给AndroidDraw作者发了邮件,询问为什么要自己重写inflate。
总结:
多读高质量的代码,从中可以学到很多东西,不仅仅是针对一个case的实现,还包括代码组织的思想。
不要坐井观天,你知道的真的太少了,不要学得什么都是半桶水,Java不知Reflection,C#不知Delegate
-------------------------------------------------------------------------------------------------------------------------------------------------
在实际开发中LayoutInflater这个类还是非常有用的,它的作用类似于findViewById()。不同点是LayoutInflater是用来找res/layout/下的xml布局文件,并且实例化;而findViewById()是找xml布局文件下的具体widget控件(如 Button、TextView等)。
具体作用:
1、对于一个没有被载入或者想要动态载入的界面,都需要使用LayoutInflater.inflate()来载入;
2、对于一个已经载入的界面,就可以使用Activiyt.findViewById()方法来获得其中的界面元素。
LayoutInflater 是一个抽象类,在文档中如下声明:
获得 LayoutInflater 实例的三种方式:
其实,这三种方式本质是相同的,从源码中可以看出:
getLayoutInflater():
Activity 的 getLayoutInflater() 方法是调用 PhoneWindow 的getLayoutInflater()方法,看一下该源代码:
可以看出它其实是调用 LayoutInflater.from(context)。
LayoutInflater.from(context):
可以看出它其实调用 context.getSystemService()。
结论:所以这三种方式最终本质是都是调用的Context.getSystemService()。
inflate 方法
通过 sdk 的 api 文档,可以知道该方法有以下几种过载形式,返回值均是 View 对象,如下:
1:
public View inflate (int resource, ViewGroup root)
reSource:View的layout的ID
root:如果为null,则将此View作为根,此时既可以应用此View中的其他控件了。
如果!null, 则将默认的layout作为View的根。
2:
public View inflate ( XmlPullParser parser, ViewGroup root)
parser:你需要解析xml的解析接口
root:如果null,则将此View作为根,此时既可以应用此View中的其他控件了。
如果!null, 则将默认的layout作为View的根。
3:
public View inflate ( XmlPullParser parser, ViewGroup root, boolean attachToRoot)
parser:你需要解析View的xml的解析接口
root:如果null,则将此View作为根,此时既可以应用此View中的其他控件了。
如果!null, 则将默认的layout作为View的根。
attachToRoot:
ture:也就将此解析的xml作为View根
fase:则为默认的xml,做为根视图View
4:
public View inflate (int resource, ViewGroup root, boolean attachToRoot)
resource:View的layout的ID
root:如果null,则将此View作为根,此时既可以应用此View中的其他控件了。
如果!null, 则将默认的layout作为View的根。
attachToRoot:
ture:也就将此解析的xml作为View根
fase:则为默认的xml,做为根视图View
示意代码:
同时在此讲讲让我去API中去理解这四个函数的原因吧!嘿嘿!你肯定又会多学一招!
在Activity中:
大家是否知道,在setContentView(new MySurfaceView(this))后,此Activity中声明的View控件,
如:TextView 为什么引用不到layout布局文件中的控件ID呢!初一看能够应用到,但是为什么编译就报空指针呢!原因:在setContentView(new MySurfaceView(this))后,此时的View变为了根视图了,虽然能应用到TextView对应的ID,但是我在 MySurfaceView中根本就没有这个对象,所以就报空指针咯!解决办法:
View view = LayoutInflater.from(this).inflate(R.layout.passover, null);注:每解析一次都会产生不同的对象
然后你再引用没问题,使用自如了。