(轉)findViewById 返回為null (自定義控件)


一.自定義控件 findViewById返回為null

首先講一個具體的問題,這幾天在做demo時,寫了一個自定義組合控件,最后在run的時候顯示這兩行報錯。原先還以為是setOnClickListener錯了,后來經過debug才發現findViewById查找我的自定義組合控件為null !

這里寫圖片描述

debug結果:

這里寫圖片描述


接下來就開始了我痛苦的找bug過程,關於這段血淚過程,來總結一下findViewById 返回為空的出錯原因。

首先回憶一下如何寫一個自定義組合控件:

  1. 將組合控件的布局,抽取到單獨的一個xml
  2. 通過一個單獨的類,去加載此段布局文件.


步驟並不復雜,可是這里卻有三個出錯點!

1. 當你在使用自定義的組合控件時,在xml文件中使用該控件時,不能簡單的寫類名,包名也要!

    <com.gym.mobile.view.SettingItemView
        android:id="@+id/siv_update"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

 

 

而不能簡單的寫一個:

 <SettingItemView
        android:id="@+id/siv_update"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>

 

 

2.【重點!】我們再寫單獨類時,必定會繼承某個類,要繼承它的構造方法,一定要注意,下面講解一下這3個構造方法:

  //使用在java代碼創建控件(無法加載XML文件中定義的控件屬性)
    public FocusTextView(Context context) {
        super(context);
    }

    //由系統調用(上下文環境構造方法 + 帶屬性)
    public FocusTextView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    //由系統調用(上下文環境構造方法 + 帶屬性 + 布局文件中定義樣式文件構造方法)
    public FocusTextView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

 

 

這里繼承的3種構造方法super調用父類一定要仔細對應!大部分錯誤都是出現在這里,而且在寫自定義控件如果涉及到自定義屬性時,一定要繼承第二個構造方法!還涉及到樣式,則第三個構造方法也要寫!!

(而我的demo錯誤就是在寫構造方法時,super調用父類構造函數時對應的參數有誤,導致findViewById 返回為null,花了好長時間 :(


3.如果還運用到自定義屬性的話,一定要在運用屬性的控件內添加該項目的xmlns

xmlns:mobilesafe="http://schemas.android.com/apk/res/com.gym.mobile"

 

 
<com.gym.mobile.view.SettingItemView
xmlns:mobilesafe="http://schemas.android.com/apk/res/com.gym.mobile"

        android:id="@+id/siv_update"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        mobilesafe:destitle="自動更新設置"
        mobilesafe:desoff="自動更新已關閉"
        mobilesafe:deson="自動更新已開啟">
    </com.itheima.mobilesafe74.view.SettingItemView>

 

 

 





二. findViewById 返回為null

以上討論的是一個特殊情況即自定義控件時,下面從整體分析findViewById 返回為null的情況,我們先好好思考findViewById的使用:

   findViewById的完整寫法是View.findViewById(),而不指定View時默認的是Context,因此當findViewById不是在context里執行時,要指定對應的View! 實例化控件時必須指定XXX.findViewById()而不能直接findViewById(),否則就會從Activity而不是特定的某個布局文件中找R.id.XXX 當然,如果findviewbuid之前加載了對應的布局,即可不必在findViewById之前寫對應的view !!!

 


關於以上這段話,也有幾個出錯點!

1.可能性最大的一種,也是很粗心的一種,你在加載視圖的操作之前使用了findViewById尋找控件Id試問視圖都沒有加載出來,控件id是找不到的。
試圖加載即:

 setContentView(R.layout.activity_splash);

(以下為錯誤示范。。。)

這里寫圖片描述




2.還有一種可能性,錯誤很隱蔽!也是關於加載視圖的問題,在尋找控件時,控件所處的xml文件要與加載的視圖相同否則setContentView中加載的視圖與你需要尋找控件所處的視圖不同,兩個毫不相關的視圖,怎么聯系到一塊?所以跟一開始思考findViewById那段話一樣,你需要在使用findViewById之前加上相應控件所處的視圖


【!!!】最典型的情況就是你在使用了 inflate特定的xml轉換成view之后,再使用findViewById找view里的控件是找不到的!,因為它這里默認的是 this.findViewById(R.id.bt_submit),
所以你需要將其改為view.findViewById(R.id.bt_submit)

錯誤示范:
這里寫圖片描述

正確改法!:

這里寫圖片描述

 

轉載自:轉載注明: http://blog.csdn.net/itermeng/article/details/52034186


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM