相信我们在开发过程中肯定接触过LayoutInflater,比如ListView的适配器里的getView方法里通过LayoutInflater.from(Context).inflater来加载xml布局,在Fragment里的onCreateView里面也是一样,加载布局一共三种方法。
1,在Activity里面调用getLayoutInflater()
2, 通过LayoutInflater.from(context).inflater()
3, context.getSystemService(Context.LAYOUT_INFLATER_SERVICE))
以上的三种方式从实现上都是一样的,Activity里面的getLayoutInflater()实际上调用的是PhoneWindow的实现,而PhoneWindow里源码的处理是LayoutInflater.from(context).inflater(),往下查找最终调用context.getSystemService。
context.getSystemService是Android里一个比较重要的api,是Activity的一个方法,根据传入的Name来取得对应的Object,然后转换成相应的服务对象。以下是系统相应的服务。
传入的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 电话服务
但是LayoutInflater.from(context).inflater()的方法这么多,那它们到底是什么样的用法呢?
/**
341 * Inflate a new view hierarchy from the specified xml resource. Throws
342 * {@link InflateException} if there is an error.
343 *
344 * @param resource ID for an XML layout resource to load (e.g.,
345 * <code>R.layout.main_page</code>)
346 * @param root Optional view to be the parent of the generated hierarchy.
347 * @return The root View of the inflated hierarchy. If root was supplied,
348 * this is the root View; otherwise it is the root of the inflated
349 * XML file.
350 */
351 public View inflate(int resource, ViewGroup root) {
352 return inflate(resource, root, root != null);
353 }
354
355 /**
356 * Inflate a new view hierarchy from the specified xml node. Throws
357 * {@link InflateException} if there is an error. *
358 * <p>
359 * <em><strong>Important</strong></em> For performance
360 * reasons, view inflation relies heavily on pre-processing of XML files
361 * that is done at build time. Therefore, it is not currently possible to
362 * use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
363 *
364 * @param parser XML dom node containing the description of the view
365 * hierarchy.
366 * @param root Optional view to be the parent of the generated hierarchy.
367 * @return The root View of the inflated hierarchy. If root was supplied,
368 * this is the root View; otherwise it is the root of the inflated
369 * XML file.
370 */
371 public View inflate(XmlPullParser parser, ViewGroup root) {
372 return inflate(parser, root, root != null);
373 }
374
375 /**
376 * Inflate a new view hierarchy from the specified xml resource. Throws
377 * {@link InflateException} if there is an error.
378 *
379 * @param resource ID for an XML layout resource to load (e.g.,
380 * <code>R.layout.main_page</code>)
381 * @param root Optional view to be the parent of the generated hierarchy (if
382 * <em>attachToRoot</em> is true), or else simply an object that
383 * provides a set of LayoutParams values for root of the returned
384 * hierarchy (if <em>attachToRoot</em> is false.)
385 * @param attachToRoot Whether the inflated hierarchy should be attached to
386 * the root parameter? If false, root is only used to create the
387 * correct subclass of LayoutParams for the root view in the XML.
388 * @return The root View of the inflated hierarchy. If root was supplied and
389 * attachToRoot is true, this is root; otherwise it is the root of
390 * the inflated XML file.
391 */
392 public View inflate(int resource, ViewGroup root, boolean attachToRoot) {
393 if (DEBUG) System.out.println("INFLATING from resource: " + resource);
394 XmlResourceParser parser = getContext().getResources().getLayout(resource);
395 try {
396 return inflate(parser, root, attachToRoot);
397 } finally {
398 parser.close();
399 }
400 }
上面的方法非常清晰,直接看下inflate(parser, root, attachToRoot);
/**
403 * Inflate a new view hierarchy from the specified XML node. Throws
404 * {@link InflateException} if there is an error.
405 * <p>
406 * <em><strong>Important</strong></em> For performance
407 * reasons, view inflation relies heavily on pre-processing of XML files
408 * that is done at build time. Therefore, it is not currently possible to
409 * use LayoutInflater with an XmlPullParser over a plain XML file at runtime.
410 *
411 * @param parser XML dom node containing the description of the view
412 * hierarchy.
413 * @param root Optional view to be the parent of the generated hierarchy (if
414 * <em>attachToRoot</em> is true), or else simply an object that
415 * provides a set of LayoutParams values for root of the returned
416 * hierarchy (if <em>attachToRoot</em> is false.)
417 * @param attachToRoot Whether the inflated hierarchy should be attached to
418 * the root parameter? If false, root is only used to create the
419 * correct subclass of LayoutParams for the root view in the XML.
420 * @return The root View of the inflated hierarchy. If root was supplied and
421 * attachToRoot is true, this is root; otherwise it is the root of
422 * the inflated XML file.
423 */
424 public View inflate(XmlPullParser parser, ViewGroup root, boolean attachToRoot) {
425 synchronized (mConstructorArgs) {
426 final AttributeSet attrs = Xml.asAttributeSet(parser);
427 Context lastContext = (Context)mConstructorArgs[0];
428 mConstructorArgs[0] = mContext;
429 View result = root;
430
431 try {
432 // Look for the root node.
433 int type;
434 while ((type = parser.next()) != XmlPullParser.START_TAG &&
435 type != XmlPullParser.END_DOCUMENT) {
436 // Empty
437 }
438
439 if (type != XmlPullParser.START_TAG) {
440 throw new InflateException(parser.getPositionDescription()
441 + ": No start tag found!");
442 }
443
444 final String name = parser.getName();
445
446 if (DEBUG) {
447 System.out.println("**************************");
448 System.out.println("Creating root view: "
449 + name);
450 System.out.println("**************************");
451 }
452
453 if (TAG_MERGE.equals(name)) {
454 if (root == null || !attachToRoot) {
455 throw new InflateException("<merge /> can be used only with a valid "
456 + "ViewGroup root and attachToRoot=true");
457 }
458
459 rInflate(parser, root, attrs, false);
460 } else {
461 // Temp is the root view that was found in the xml
462 View temp;
463 if (TAG_1995.equals(name)) {
464 temp = new BlinkLayout(mContext, attrs);
465 } else {
466 temp = createViewFromTag(root, name, attrs);
467 }
468
469 ViewGroup.LayoutParams params = null;
470 // 当父层不为空时
471 if (root != null) {
472 if (DEBUG) {
473 System.out.println("Creating params from root: " +
474 root);
475 }
476 // Create layout params that match root, if supplied
// 获取父层的参数并赋值
477 params = root.generateLayoutParams(attrs);
// 子布局不贴上也会被设置LayoutParams
478 if (!attachToRoot) {
479 // Set the layout params for temp if we are not
480 // attaching. (If we are, we use addView, below)
481 temp.setLayoutParams(params);
482 }
483 }
484
485 if (DEBUG) {
486 System.out.println("-----> start inflating children");
487 }
488 // Inflate all children under temp
489 rInflate(parser, temp, attrs, true);
490 if (DEBUG) {
491 System.out.println("-----> done inflating children");
492 }
493
494 // We are supposed to attach all the views we found (int temp)
495 // to root. Do that now.
// 父布局不为空并且贴上会被add到父层
496 if (root != null && attachToRoot) {
497 root.addView(temp, params);
498 }
499
500 // Decide whether to return the root that was passed in or the
501 // top view found in xml.
// 父布局为空或者没有贴上,result就是View本身
502 if (root == null || !attachToRoot) {
503 result = temp;
504 }
505 }
506
507 } catch (XmlPullParserException e) {
508 InflateException ex = new InflateException(e.getMessage());
509 ex.initCause(e);
510 throw ex;
511 } catch (IOException e) {
512 InflateException ex = new InflateException(
513 parser.getPositionDescription()
514 + ": " + e.getMessage());
515 ex.initCause(e);
516 throw ex;
517 } finally {
518 // Don't retain static reference on context.
519 mConstructorArgs[0] = lastContext;
520 mConstructorArgs[1] = null;
521 }
522 // 最后返回 result
523 return result;
524 }
525 }
由上源码我们可以得出:
inflate(layout, null)返回的是View本身,且View本身所设置的布局参数无效,由父层和子View决定大小。
inflate(layout, null, false)同上一样,当父层为空,第三个值是否为真没有意义
inflate(layout, parent)子布局会被加入到父层并设置布局参数,具体大小由父层和子View决定
inflate(layout, parent, false)同上一样,区别就是false返回的是子View本身。
inflate(layout, parent, true)同第三个方法一样,返回父层View