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文件中使用该控件时,不能简单的写类名,包名也要!

    <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)

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

正确改法!:

这里写图片描述

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

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值