欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android中使用LayoutInflater要注意的一些坑

 更新時(shí)間:2017年04月25日 16:38:55   作者:Android雜貨鋪  
LayoutInflater類在我們?nèi)粘i_(kāi)發(fā)中經(jīng)常會(huì)用到,最近在使用中就遇到了一些問(wèn)題,所有下面這篇文章主要給大家總結(jié)了關(guān)于Android中使用LayoutInflater要注意的一些坑,希望通過(guò)這篇能讓大家避免走一些彎路,需要的朋友可以參考學(xué)習(xí),下面來(lái)一起看吧。

前言

在平時(shí)的開(kāi)發(fā)過(guò)程中,我們經(jīng)常會(huì)用LayoutInflater這個(gè)類,比如說(shuō)在Fragment$onCreateViewRecyclerView.Adapter$onCreateViewHolder中都會(huì)用到。它的用法也無(wú)非就是LayoutInflater.inflate(resourceId, root, attachToRoot),第一個(gè)參數(shù)沒(méi)什么好說(shuō)的,但第二個(gè)和第三個(gè)參數(shù)結(jié)合起來(lái)會(huì)帶來(lái)一定的迷惑性。之前有時(shí)候會(huì)發(fā)現(xiàn)界面布局上出了一些問(wèn)題,查了很久之后偶然的改動(dòng)了這兩個(gè)參數(shù),發(fā)現(xiàn)問(wèn)題解決了,然后也就過(guò)去了,并沒(méi)有去思考這是為什么,然后下次可能又重復(fù)這種困境了。

所以想在這里總結(jié)一下,避免以后繼續(xù)掉坑。

先來(lái)看看inflate方法的注釋:

/**
 * Inflate a new view hierarchy from the specified xml resource. Throws
 * {@link InflateException} if there is an error.
 * 
 * @param resource ID for an XML layout resource to load (e.g.,
 *  <code>R.layout.main_page</code>)
 * @param root Optional view to be the parent of the generated hierarchy (if
 *  <em>attachToRoot</em> is true), or else simply an object that
 *  provides a set of LayoutParams values for root of the returned
 *  hierarchy (if <em>attachToRoot</em> is false.)
 * @param attachToRoot Whether the inflated hierarchy should be attached to
 *  the root parameter? If false, root is only used to create the
 *  correct subclass of LayoutParams for the root view in the XML.
 * @return The root View of the inflated hierarchy. If root was supplied and
 *   attachToRoot is true, this is root; otherwise it is the root of
 *   the inflated XML file.
 */
public View inflate(@LayoutRes int resource, @Nullable ViewGroup root, boolean attachToRoot)

首先需要了解的一點(diǎn)是,一個(gè)View的測(cè)量結(jié)果并不只是由它自己的layout_width和layout_height(即LayoutParams)所決定的,而是由父容器給它的約束(MeasureSpec)和它自身的LayoutParams共同決定的。

達(dá)成這個(gè)共識(shí)之后,我們?cè)賮?lái)看看它的參數(shù)。

  • root:給布局文件提供一個(gè)父容器。布局文件里面總有一個(gè)元素是沒(méi)有父容器的(沒(méi)錯(cuò),就是根元素),所以需要給它提供一個(gè)父容器來(lái)幫助它完成測(cè)量工作。如果root為空的話,就會(huì)導(dǎo)致根元素中的layout_xxx全部失效,從而影響到整個(gè)布局。同時(shí),如果root為空的話,那么attachToRoot也就沒(méi)有意義了。
  • attachToRoot: 如果為true,創(chuàng)建出來(lái)的布局系統(tǒng)會(huì)幫我們添加到父容器中去。為false的話,就只是給它提供約束,好讓這個(gè)布局順利完成測(cè)量等工作而已,將布局添加到父容器中去需要我們后續(xù)根據(jù)需要去手動(dòng)調(diào)用addView方法。
  • 返回值:如果root != null && attachToRoot,返回的View就是傳進(jìn)來(lái)的root,否則返回由布局文件所創(chuàng)建的View對(duì)象。

用幾個(gè)例子來(lái)說(shuō)明一下會(huì)比較好理解。Activity的布局是一個(gè)LinearLayout,要添加的布局如下:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/item_text"
  android:layout_width="200dp"
  android:layout_height="50dp"
  android:layout_marginLeft="16dp"
  android:layout_marginTop="16dp"
  android:background="@color/colorAccent"
  android:gravity="center"
  android:text="item: text"/>

正常的情況

// 第一種方法
View inflatedView = LayoutInflater.from(this).inflate(R.layout.item_text, mLinearLayout, true);
Log.d(TAG, "inflated view is " + inflatedView);

// 第二種方法
View inflatedView = LayoutInflater.from(this).inflate(R.layout.item_text, mLinearLayout, false);
Log.d(TAG, "inflated view is " + inflatedView);
mLinearLayout.addView(inflatedView);

視覺(jué)上的結(jié)果都是一樣的


但是Log就有一點(diǎn)不一樣了,這就是attachToRoot不同的值所導(dǎo)致的。

第一種方法的Log

D/MainActivity: inflated view is android.widget.LinearLayout{36e9aac V.E...... ......I. 0,0-0,0 #7f0c0051 app:id/linear}

第二種方法的Log

D/MainActivity: inflated view is android.support.v7.widget.AppCompatTextView{3c9d37b V.ED..... ......ID 0,0-0,0 #7f0c0054 app:id/item_text}

還有一個(gè)需要注意的地方是:如果在第一種方法的基礎(chǔ)上再加上mLinearLayout.addView(inflatedView)就會(huì)造成報(bào)錯(cuò)
IllegalStateException: The specified child already has a parent....  。

而如果第二種方法沒(méi)有這句話,界面上是看不到任何東西的。

root為null的情況

mLinearLayout = (LinearLayout) findViewById(R.id.linear);
View inflatedView = LayoutInflater.from(this).inflate(R.layout.item_text, null);
Log.d(TAG, "inflated view is " + inflatedView);
mLinearLayout.addView(inflatedView);

此時(shí)再看看它的布局文件:

<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/item_text"
  android:layout_width="200dp"
  android:layout_height="50dp"
  android:layout_marginLeft="16dp"
  android:layout_marginTop="16dp"
  android:background="@color/colorAccent"
  android:gravity="center"
  android:text="item: text"/>

不難發(fā)現(xiàn),所有l(wèi)ayout_xxx的屬性全都失效了。

RecyclerView中的Inflater

上面說(shuō)了,在創(chuàng)建布局的時(shí)候,要把布局添加到root中去,并且有兩種方法,但是我們?cè)趏nCreateViewHolder中添加布局的時(shí)候卻是這樣寫的:

@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
 View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text, parent, false);
 return new MyViewHolder(view);
}

如果第三個(gè)參數(shù)傳了true還會(huì)報(bào)錯(cuò),這又是為什么呢?

java.lang.IllegalStateException: The specified child already has a parent.

直觀上來(lái)解釋就是,子View的添加與刪除是由RecyclerView來(lái)管理的,不需要我們來(lái)添加。但我們還是從RecyclerView的代碼來(lái)理解一下會(huì)好一些。

以LinearLayoutManager為例,RecyclerView在創(chuàng)建子View的時(shí)候會(huì)調(diào)用到LinearLayoutManager$layoutChunk方法:

void layoutChunk(RecyclerView.Recycler recycler, RecyclerView.State state,
  LayoutState layoutState, LayoutChunkResult result) {
 // 在這里會(huì)調(diào)用到Adapter$onCreateViewHolder
 View view = layoutState.next(recycler);
 if (view == null) {
  if (DEBUG && layoutState.mScrapList == null) {
   throw new RuntimeException("received null view when unexpected");
  }
  // if we are laying out views in scrap, this may return null which means there is
  // no more items to layout.
  result.mFinished = true;
  return;
 }
 LayoutParams params = (LayoutParams) view.getLayoutParams();
 if (layoutState.mScrapList == null) {
  if (mShouldReverseLayout == (layoutState.mLayoutDirection
    == LayoutState.LAYOUT_START)) {
   addView(view);
  } else {
   addView(view, 0);
  }
 } else {
  if (mShouldReverseLayout == (layoutState.mLayoutDirection
    == LayoutState.LAYOUT_START)) {
   addDisappearingView(view);
  } else {
   addDisappearingView(view, 0);
  }
 }

 // 省略其它大部分代碼
}

在初始化的時(shí)候,View view = layoutState.next(recycler)里面會(huì)調(diào)用到我們熟悉的onCreateViewHolder方法,然后我們?cè)诶锩鎖nflate的過(guò)程中第三個(gè)參數(shù)傳了true,將子View添加到了RecyclerView中去了。然而,獲得View之后,調(diào)用到了addView(因?yàn)槭浅跏蓟?,不可能調(diào)用addDisappearingView) ,這里又會(huì)去添加一次,所以報(bào)出了上面的IllegalStateException異常。

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)各位Android開(kāi)發(fā)者們能帶來(lái)一定的幫助,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • Android入門教程之Picasso框架

    Android入門教程之Picasso框架

    本文會(huì)先介紹Picasso的基本使用方法,讓您快速上手Picasso。后面我們分享實(shí)現(xiàn)ListView顯示網(wǎng)絡(luò)圖片的實(shí)例,從源碼角度詳細(xì)分析它的實(shí)現(xiàn),有需要的可以參考借鑒。
    2016-08-08
  • android上一個(gè)可追蹤代碼具體到函數(shù)某行的日志類

    android上一個(gè)可追蹤代碼具體到函數(shù)某行的日志類

    追蹤代碼到函數(shù)具體某行,這樣的功能,是每一個(gè)程序員都希望會(huì)有的,因?yàn)樗梢詭椭覀冏粉櫟侥承写a的錯(cuò)誤,接下來(lái)介紹下android上一個(gè)可追蹤代碼到函數(shù)具體某行的日志類,希望對(duì)開(kāi)發(fā)者有所幫助
    2012-12-12
  • Android 7.0 運(yùn)行時(shí)權(quán)限彈窗問(wèn)題的解決

    Android 7.0 運(yùn)行時(shí)權(quán)限彈窗問(wèn)題的解決

    這篇文章主要介紹了Android 7.0 運(yùn)行時(shí)權(quán)限彈窗問(wèn)題的解決,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-03-03
  • Android WiFi熱點(diǎn)開(kāi)發(fā)的示例代碼

    Android WiFi熱點(diǎn)開(kāi)發(fā)的示例代碼

    這篇文章主要介紹了Android WiFi熱點(diǎn)開(kāi)發(fā)的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Android程序開(kāi)發(fā)ListView+Json+異步網(wǎng)絡(luò)圖片加載+滾動(dòng)翻頁(yè)的例子(圖片能緩存,圖片不錯(cuò)亂)

    Android程序開(kāi)發(fā)ListView+Json+異步網(wǎng)絡(luò)圖片加載+滾動(dòng)翻頁(yè)的例子(圖片能緩存,圖片不錯(cuò)亂)

    這篇文章主要介紹了Android程序開(kāi)發(fā)ListView+Json+異步網(wǎng)絡(luò)圖片加載+滾動(dòng)翻頁(yè)的例子(圖片能緩存,圖片不錯(cuò)亂) 的相關(guān)資料,需要的朋友可以參考下
    2016-01-01
  • Android中volley封裝實(shí)踐記錄(二)

    Android中volley封裝實(shí)踐記錄(二)

    這篇文章主要給大家介紹了關(guān)于Android中volley封裝的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-02-02
  • Android使用SlidingPaneLayout 實(shí)現(xiàn)仿微信的滑動(dòng)返回

    Android使用SlidingPaneLayout 實(shí)現(xiàn)仿微信的滑動(dòng)返回

    這篇文章主要介紹了Android使用SlidingPaneLayout 實(shí)現(xiàn)仿微信的滑動(dòng)返回,需要的朋友可以參考下
    2018-04-04
  • Android Eclipse 注釋模板的使用(圖文說(shuō)明)

    Android Eclipse 注釋模板的使用(圖文說(shuō)明)

    為提高代碼的可讀性以及后期的可維護(hù)性,為我們的代碼加上規(guī)范化的注釋是很有必要,不僅有利于提高自己的專業(yè)素養(yǎng),也能方便他人
    2013-12-12
  • Android顯式Intent與隱式Intent的使用詳解

    Android顯式Intent與隱式Intent的使用詳解

    Intent的中文意思是“意圖,意向”, Intent對(duì)Android的核心和靈魂,是各組件之間的橋梁。四大組件分別為Activity 、Service、BroadcastReceiver、ContentProvider。而這四種組件是獨(dú)立的,它們之間可以互相調(diào)用,協(xié)調(diào)工作,最終組成一個(gè)真正的Android應(yīng)用
    2022-09-09
  • 簡(jiǎn)單談?wù)勎业腁ndroid屏幕適配之路

    簡(jiǎn)單談?wù)勎业腁ndroid屏幕適配之路

    我相信Android碎片化問(wèn)題是讓所有的Android開(kāi)發(fā)者都比較頭疼的問(wèn)題.尤其是屏幕適配這一塊兒.想要自己的app在不同的設(shè)備上面都有一個(gè)比較好的顯示效果.就必須做好相應(yīng)的屏幕適配.
    2017-11-11

最新評(píng)論