Anroid studio遇到的问题7--- findViewById 返回为null (自定义控件)

7. findViewById 返回为null (自定义控件)

http://blog.csdn.net/itermeng/article/details/52034186

一.自定义控件 findViewById返回为null

首先讲一个具体的问题,这几天在做demo时,写了一个自定义组合控件,最后在run的时候显示这两行报错。原先还以为是setOnClickListener错了,后来经过debug才发现findViewById查找我的自定义组合控件为null !

这里写图片描述

debug结果:

这里写图片描述


接下来就开始了我痛苦的找bug过程,关于这段血泪过程,来总结一下findViewById 返回为空的出错原因。

首先回忆一下如何写一个自定义组合控件:

  1. 将组合控件的布局,抽取到单独的一个xml
  2. 通过一个单独的类,去加载此段布局文件.


步骤并不复杂,可是这里却有三个出错点!

1. 当你在使用自定义的组合控件时,在xml文件中使用该控件时,不能简单的写类名,包名也要!

<code class="hljs avrasm has-numbering">    <<span class="hljs-keyword">com</span><span class="hljs-preprocessor">.gym</span><span class="hljs-preprocessor">.mobile</span><span class="hljs-preprocessor">.view</span><span class="hljs-preprocessor">.SettingItemView</span>
        android:id=<span class="hljs-string">"@+id/siv_update"</span>
        android:layout_width=<span class="hljs-string">"match_parent"</span>
        android:layout_height=<span class="hljs-string">"wrap_content"</span>/></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

而不能简单的写一个:

<code class="hljs xml has-numbering"> <span class="hljs-tag"><<span class="hljs-title">SettingItemView
</span>        <span class="hljs-attribute">android:id</span>=<span class="hljs-value">"@+id/siv_update"</span>
        <span class="hljs-attribute">android:layout_width</span>=<span class="hljs-value">"match_parent"</span>
        <span class="hljs-attribute">android:layout_height</span>=<span class="hljs-value">"wrap_content"</span>/></span></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li></ul>

2.【重点!】我们再写单独类时,必定会继承某个类,要继承它的构造方法,一定要注意,下面讲解一下这3个构造方法:

<code class="hljs java has-numbering">    <span class="hljs-comment">//使用在java代码创建控件(无法加载XML文件中定义的控件属性)</span>
    <span class="hljs-keyword">public</span> <span class="hljs-title">FocusTextView</span>(Context context) {
        <span class="hljs-keyword">super</span>(context);
    }

    <span class="hljs-comment">//由系统调用(上下文环境构造方法 + 带属性)</span>
    <span class="hljs-keyword">public</span> <span class="hljs-title">FocusTextView</span>(Context context, AttributeSet attrs) {
        <span class="hljs-keyword">super</span>(context, attrs);
    }

    <span class="hljs-comment">//由系统调用(上下文环境构造方法 + 带属性 + 布局文件中定义样式文件构造方法)</span>
    <span class="hljs-keyword">public</span> <span class="hljs-title">FocusTextView</span>(Context context, AttributeSet attrs, <span class="hljs-keyword">int</span> defStyle) {
        <span class="hljs-keyword">super</span>(context, attrs, defStyle);
    }</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li><li>11</li><li>12</li><li>13</li><li>14</li></ul>

这里继承的3种构造方法super调用父类一定要仔细对应!大部分错误都是出现在这里,而且在写自定义控件如果涉及到自定义属性时,一定要继承第二个构造方法!还涉及到样式,则第三个构造方法也要写!!

(而我的demo错误就是在写构造方法时,super调用父类构造函数时对应的参数有误,导致findViewById 返回为null,花了好长时间 :(


3.如果还运用到自定义属性的话,一定要在运用属性的控件内添加该项目的xmlns

<code class="hljs avrasm has-numbering"><span class="hljs-label">xmlns:</span>mobilesafe=<span class="hljs-string">"http://schemas.android.com/apk/res/com.gym.mobile"</span></code><ul style="" class="pre-numbering"><li>1</li></ul>
<code class="hljs avrasm has-numbering"><<span class="hljs-keyword">com</span><span class="hljs-preprocessor">.gym</span><span class="hljs-preprocessor">.mobile</span><span class="hljs-preprocessor">.view</span><span class="hljs-preprocessor">.SettingItemView</span>
<span class="hljs-label">xmlns:</span>mobilesafe=<span class="hljs-string">"http://schemas.android.com/apk/res/com.gym.mobile"</span>

        android:id=<span class="hljs-string">"@+id/siv_update"</span>
        android:layout_width=<span class="hljs-string">"match_parent"</span>
        android:layout_height=<span class="hljs-string">"wrap_content"</span>
        mobilesafe:destitle=<span class="hljs-string">"自动更新设置"</span>
        mobilesafe:desoff=<span class="hljs-string">"自动更新已关闭"</span>
        mobilesafe:deson=<span class="hljs-string">"自动更新已开启"</span>>
    </<span class="hljs-keyword">com</span><span class="hljs-preprocessor">.itheima</span><span class="hljs-preprocessor">.mobilesafe</span>74<span class="hljs-preprocessor">.view</span><span class="hljs-preprocessor">.SettingItemView</span>></code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li><li>7</li><li>8</li><li>9</li><li>10</li></ul>




二. findViewById 返回为null

以上讨论的是一个特殊情况即自定义控件时,下面从整体分析findViewById 返回为null的情况,我们先好好思考findViewById的使用:

<code class="hljs avrasm has-numbering">   findViewById的完整写法是View<span class="hljs-preprocessor">.findViewById</span>(),而不指定View时默认的是Context,因此当findViewById不是在context里执行时,要指定对应的View!

   实例化控件时必须指定XXX<span class="hljs-preprocessor">.findViewById</span>()而不能直接findViewById(),否则就会从Activity而不是特定的某个布局文件中找R<span class="hljs-preprocessor">.id</span><span class="hljs-preprocessor">.XXX</span>

当然,如果findviewbuid之前加载了对应的布局,即可不必在findViewById之前写对应的view  !!!</code><ul style="" class="pre-numbering"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li></ul>

关于以上这段话,也有几个出错点!

1.可能性最大的一种,也是很粗心的一种,你在加载视图的操作之前使用了findViewById寻找控件Id试问视图都没有加载出来,控件id是找不到的。
试图加载即:

<code class="hljs avrasm has-numbering"> setContentView(R<span class="hljs-preprocessor">.layout</span><span class="hljs-preprocessor">.activity</span>_splash)<span class="hljs-comment">;</span></code><ul style="" class="pre-numbering"><li>1</li></ul>

(以下为错误示范。。。)

这里写图片描述




2.还有一种可能性,错误很隐蔽!也是关于加载视图的问题,在寻找控件时,控件所处的xml文件要与加载的视图相同否则setContentView中加载的视图与你需要寻找控件所处的视图不同,两个毫不相关的视图,怎么联系到一块?所以跟一开始思考findViewById那段话一样,你需要在使用findViewById之前加上相应控件所处的视图


【!!!】最典型的情况就是你在使用了 inflate特定的xml转换成view之后,再使用findViewById找view里的控件是找不到的!,因为它这里默认的是 this.findViewById(R.id.bt_submit),
所以你需要将其改为view.findViewById(R.id.bt_submit)

错误示范:
这里写图片描述

正确改法!:

这里写图片描述

(bug天天有,一个小bug整死人,大家一定要注意!持续更新中。。。。。。:)

展开阅读全文

没有更多推荐了,返回首页