Android开发中getViewById为什么返回null
2个回答
2016-04-15 · 百度知道合伙人官方认证企业
育知同创教育
1【专注:Python+人工智能|Java大数据|HTML5培训】 2【免费提供名师直播课堂、公开课及视频教程】 3【地址:北京市昌平区三旗百汇物美大卖场2层,微信公众号:yuzhitc】
向TA提问
关注
展开全部
一,调用顺序不当导致的异常
持这种观点的主要原因是getViewById的调用放到了setContentView之前,如下:
super.onCreate(savedInstanceState);
mTrueButton = (Button)getViewById(R.id.true_button);
setContentView(R.layout.activity_quiz);
理由是:当activity 调用 setContentView() 时,android 才会去绘制 layout 上的各个元素,并为其分配内存。只有 分配了内存以后,才能继续执行 ,findViewById(); 才能得到引用,不然得到空引用,空引用意味着,后面使用相应变量时就会发生访问的对象不存在的问题。
而且当Activity重新setContentView()以后,那些之前绘制的控件,内存都被灭掉了。
所以,若是通过setContentView 来达到画面切换目的的,要注意重新绘制以后重新取得引用
二,getViewById的上下文对象不匹配
这种方式让笔者想到Javascript中的document.getElementById,两者具有非常高的相似性,getElementById的调用需要指定对应的document对象,表示从该document对象获取元素,同理,Android中的getViewById的完整调用是View.getViewById,因此需要关注该方法默认的context对象,一般是this,即当前的Activity,但有时候可能不是这样,如:
userDialog=new Dialog(addevent.this);
userDialog.setContentView(R.layout.user_list);
userDialog.setTitle("请选择");
ListView lv=(ListView)userDialog.findViewById(R.id.userList);
lv.setAdapter(new MyAdapter());
userDialog.show();
如上,实例化lv时必须指定userDialog.findViewById()而不能直接findViewById(),否则就会从Activity而不是Dialog的布局文件中找R.id.userList,此时当然会返回null,执行lv.setAdapter(new MyAdapter());时就会出现NullPointException异常
三,开发工具Eclipse导致的问题
假定在自定的Adapter的getView方法中有类似如下的代码:
View rowview = (View)inflater.inflate(R.layout.rowview, parent, false);
TextView tv_contact_id =(TextView)rowview.findViewById(R.id.tv_contact_id);
TextView tv_contactname =(TextView)rowview.findViewById(R.id.tv_contactname);
有时候居然也会发现rowview非空,但tv_contact_id和tv_contactname都是null!仔细看代码,怎么也看不出错误来。到底是什么原因造成的呢?答案是Eclipse造成的,要解决这个问题,需要这个项目clean一次(Project菜单 -> Clean子菜单),这样就OK了。
四,新版本SDK不能在onCreate方法中调用了。
重要的环境交代:刚学Android,在官网下载的新版的ADT以及新版的SDK在新版的IDE(ADT)创建项目时如果你的最小版本(minimumrequiredSDK)要支持4.0以下版,并且目标版本为(4.0+),那么此时IDE会为你创建一个兼容包(appcompat_v7)创建项目后,这个时候在生成的项目主Activity不是以前的那种继承的Activity,而是继承的ActionBarActivity。
此时,如果你仍然用旧的办法在onCreate调用getViewById,那么会返回null,原因是:在新的layout文件不是存放在默认的(res/layout/activity_quiz.xml)文件中,而是存放在(res/layout/fragment_quiz.xml)文件中。所以要在fragment_quiz.xml去找对应的ID才会找到,而新的IDE生成的代码中加载(fragment_quiz.xml)文件是在一个内部类加载的,所以一种方法是:我们可以在内部类加载处来得到Button。
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
View rootView = null;
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_quiz, container, false);
mTrueButton = (Button) rootView.findViewById(R.id.true_button);
System.out.println(button);
return rootView;
}
}
另外一种方法是:如果熟悉Activity的生命周期的人可以知道:onCreate调用的时候其实还没构造对应的布局对象,因此不能在onCreate函数中获取控件,但可以在onStart函数中获取
@Override
protected void onStart() {
super.onStart();
mTrueButton = (Button)findViewById(R.id.true_button);
mTrueButton.setOnClickListener(new android.view.View.OnClickListener(){
public void onClick(android.view.View v) {
//TODO...
}
});
}
持这种观点的主要原因是getViewById的调用放到了setContentView之前,如下:
super.onCreate(savedInstanceState);
mTrueButton = (Button)getViewById(R.id.true_button);
setContentView(R.layout.activity_quiz);
理由是:当activity 调用 setContentView() 时,android 才会去绘制 layout 上的各个元素,并为其分配内存。只有 分配了内存以后,才能继续执行 ,findViewById(); 才能得到引用,不然得到空引用,空引用意味着,后面使用相应变量时就会发生访问的对象不存在的问题。
而且当Activity重新setContentView()以后,那些之前绘制的控件,内存都被灭掉了。
所以,若是通过setContentView 来达到画面切换目的的,要注意重新绘制以后重新取得引用
二,getViewById的上下文对象不匹配
这种方式让笔者想到Javascript中的document.getElementById,两者具有非常高的相似性,getElementById的调用需要指定对应的document对象,表示从该document对象获取元素,同理,Android中的getViewById的完整调用是View.getViewById,因此需要关注该方法默认的context对象,一般是this,即当前的Activity,但有时候可能不是这样,如:
userDialog=new Dialog(addevent.this);
userDialog.setContentView(R.layout.user_list);
userDialog.setTitle("请选择");
ListView lv=(ListView)userDialog.findViewById(R.id.userList);
lv.setAdapter(new MyAdapter());
userDialog.show();
如上,实例化lv时必须指定userDialog.findViewById()而不能直接findViewById(),否则就会从Activity而不是Dialog的布局文件中找R.id.userList,此时当然会返回null,执行lv.setAdapter(new MyAdapter());时就会出现NullPointException异常
三,开发工具Eclipse导致的问题
假定在自定的Adapter的getView方法中有类似如下的代码:
View rowview = (View)inflater.inflate(R.layout.rowview, parent, false);
TextView tv_contact_id =(TextView)rowview.findViewById(R.id.tv_contact_id);
TextView tv_contactname =(TextView)rowview.findViewById(R.id.tv_contactname);
有时候居然也会发现rowview非空,但tv_contact_id和tv_contactname都是null!仔细看代码,怎么也看不出错误来。到底是什么原因造成的呢?答案是Eclipse造成的,要解决这个问题,需要这个项目clean一次(Project菜单 -> Clean子菜单),这样就OK了。
四,新版本SDK不能在onCreate方法中调用了。
重要的环境交代:刚学Android,在官网下载的新版的ADT以及新版的SDK在新版的IDE(ADT)创建项目时如果你的最小版本(minimumrequiredSDK)要支持4.0以下版,并且目标版本为(4.0+),那么此时IDE会为你创建一个兼容包(appcompat_v7)创建项目后,这个时候在生成的项目主Activity不是以前的那种继承的Activity,而是继承的ActionBarActivity。
此时,如果你仍然用旧的办法在onCreate调用getViewById,那么会返回null,原因是:在新的layout文件不是存放在默认的(res/layout/activity_quiz.xml)文件中,而是存放在(res/layout/fragment_quiz.xml)文件中。所以要在fragment_quiz.xml去找对应的ID才会找到,而新的IDE生成的代码中加载(fragment_quiz.xml)文件是在一个内部类加载的,所以一种方法是:我们可以在内部类加载处来得到Button。
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
View rootView = null;
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_quiz, container, false);
mTrueButton = (Button) rootView.findViewById(R.id.true_button);
System.out.println(button);
return rootView;
}
}
另外一种方法是:如果熟悉Activity的生命周期的人可以知道:onCreate调用的时候其实还没构造对应的布局对象,因此不能在onCreate函数中获取控件,但可以在onStart函数中获取
@Override
protected void onStart() {
super.onStart();
mTrueButton = (Button)findViewById(R.id.true_button);
mTrueButton.setOnClickListener(new android.view.View.OnClickListener(){
public void onClick(android.view.View v) {
//TODO...
}
});
}
展开全部
一,调用顺序不当导致的异常
持这种观点的主要原因是getViewById的调用放到了setContentView之前,如下:
super.onCreate(savedInstanceState);
mTrueButton = (Button)getViewById(R.id.true_button);
setContentView(R.layout.activity_quiz);
理由是:当activity 调用 setContentView() 时,android 才会去绘制 layout 上的各个元素,并为其分配内存。只有 分配了内存以后,才能继续执行 ,findViewById(); 才能得到引用,不然得到空引用,空引用意味着,后面使用相应变量时就会发生访问的对象不存在的问题。
而且当Activity重新setContentView()以后,那些之前绘制的控件,内存都被灭掉了。
所以,若是通过setContentView 来达到画面切换目的的,要注意重新绘制以后重新取得引用
二,getViewById的上下文对象不匹配
这种方式让笔者想到Javascript中的document.getElementById,两者具有非常高的相似性,getElementById的调用需要指定对应的document对象,表示从该document对象获取元素,同理,Android中的getViewById的完整调用是View.getViewById,因此需要关注该方法默认的context对象,一般是this,即当前的Activity,但有时候可能不是这样,如:
userDialog=new Dialog(addevent.this);
userDialog.setContentView(R.layout.user_list);
userDialog.setTitle("请选择");
ListView lv=(ListView)userDialog.findViewById(R.id.userList);
lv.setAdapter(new MyAdapter());
userDialog.show();
如上,实例化lv时必须指定userDialog.findViewById()而不能直接findViewById(),否则就会从Activity而不是Dialog的布局文件中找R.id.userList,此时当然会返回null,执行lv.setAdapter(new MyAdapter());时就会出现NullPointException异常
三,开发工具Eclipse导致的问题
假定在自定的Adapter的getView方法中有类似如下的代码:
View rowview = (View)inflater.inflate(R.layout.rowview, parent, false);
TextView tv_contact_id =(TextView)rowview.findViewById(R.id.tv_contact_id);
TextView tv_contactname =(TextView)rowview.findViewById(R.id.tv_contactname);
有时候居然也会发现rowview非空,但tv_contact_id和tv_contactname都是null!仔细看代码,怎么也看不出错误来。到底是什么原因造成的呢?答案是Eclipse造成的,要解决这个问题,需要这个项目clean一次(Project菜单 -> Clean子菜单),这样就OK了。
四,新版本SDK不能在onCreate方法中调用了。
重要的环境交代:刚学Android,在官网下载的新版的ADT以及新版的SDK在新版的IDE(ADT)创建项目时如果你的最小版本(minimumrequiredSDK)要支持4.0以下版,并且目标版本为(4.0+),那么此时IDE会为你创建一个兼容包(appcompat_v7)创建项目后,这个时候在生成的项目主Activity不是以前的那种继承的Activity,而是继承的ActionBarActivity。
此时,如果你仍然用旧的办法在onCreate调用getViewById,那么会返回null,原因是:在新的layout文件不是存放在默认的(res/layout/activity_quiz.xml)文件中,而是存放在(res/layout/fragment_quiz.xml)文件中。所以要在fragment_quiz.xml去找对应的ID才会找到,而新的IDE生成的代码中加载(fragment_quiz.xml)文件是在一个内部类加载的,所以一种方法是:我们可以在内部类加载处来得到Button。
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
View rootView = null;
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_quiz, container, false);
mTrueButton = (Button) rootView.findViewById(R.id.true_button);
System.out.println(button);
return rootView;
}
}
另外一种方法是:如果熟悉Activity的生命周期的人可以知道:onCreate调用的时候其实还没构造对应的布局对象,因此不能在onCreate函数中获取控件,但可以在onStart函数中获取
@Override
protected void onStart() {
super.onStart();
mTrueButton = (Button)findViewById(R.id.true_button);
mTrueButton.setOnClickListener(new android.view.View.OnClickListener(){
public void onClick(android.view.View v) {
//TODO...
}
});
}
持这种观点的主要原因是getViewById的调用放到了setContentView之前,如下:
super.onCreate(savedInstanceState);
mTrueButton = (Button)getViewById(R.id.true_button);
setContentView(R.layout.activity_quiz);
理由是:当activity 调用 setContentView() 时,android 才会去绘制 layout 上的各个元素,并为其分配内存。只有 分配了内存以后,才能继续执行 ,findViewById(); 才能得到引用,不然得到空引用,空引用意味着,后面使用相应变量时就会发生访问的对象不存在的问题。
而且当Activity重新setContentView()以后,那些之前绘制的控件,内存都被灭掉了。
所以,若是通过setContentView 来达到画面切换目的的,要注意重新绘制以后重新取得引用
二,getViewById的上下文对象不匹配
这种方式让笔者想到Javascript中的document.getElementById,两者具有非常高的相似性,getElementById的调用需要指定对应的document对象,表示从该document对象获取元素,同理,Android中的getViewById的完整调用是View.getViewById,因此需要关注该方法默认的context对象,一般是this,即当前的Activity,但有时候可能不是这样,如:
userDialog=new Dialog(addevent.this);
userDialog.setContentView(R.layout.user_list);
userDialog.setTitle("请选择");
ListView lv=(ListView)userDialog.findViewById(R.id.userList);
lv.setAdapter(new MyAdapter());
userDialog.show();
如上,实例化lv时必须指定userDialog.findViewById()而不能直接findViewById(),否则就会从Activity而不是Dialog的布局文件中找R.id.userList,此时当然会返回null,执行lv.setAdapter(new MyAdapter());时就会出现NullPointException异常
三,开发工具Eclipse导致的问题
假定在自定的Adapter的getView方法中有类似如下的代码:
View rowview = (View)inflater.inflate(R.layout.rowview, parent, false);
TextView tv_contact_id =(TextView)rowview.findViewById(R.id.tv_contact_id);
TextView tv_contactname =(TextView)rowview.findViewById(R.id.tv_contactname);
有时候居然也会发现rowview非空,但tv_contact_id和tv_contactname都是null!仔细看代码,怎么也看不出错误来。到底是什么原因造成的呢?答案是Eclipse造成的,要解决这个问题,需要这个项目clean一次(Project菜单 -> Clean子菜单),这样就OK了。
四,新版本SDK不能在onCreate方法中调用了。
重要的环境交代:刚学Android,在官网下载的新版的ADT以及新版的SDK在新版的IDE(ADT)创建项目时如果你的最小版本(minimumrequiredSDK)要支持4.0以下版,并且目标版本为(4.0+),那么此时IDE会为你创建一个兼容包(appcompat_v7)创建项目后,这个时候在生成的项目主Activity不是以前的那种继承的Activity,而是继承的ActionBarActivity。
此时,如果你仍然用旧的办法在onCreate调用getViewById,那么会返回null,原因是:在新的layout文件不是存放在默认的(res/layout/activity_quiz.xml)文件中,而是存放在(res/layout/fragment_quiz.xml)文件中。所以要在fragment_quiz.xml去找对应的ID才会找到,而新的IDE生成的代码中加载(fragment_quiz.xml)文件是在一个内部类加载的,所以一种方法是:我们可以在内部类加载处来得到Button。
/**
* A placeholder fragment containing a simple view.
*/
public static class PlaceholderFragment extends Fragment {
View rootView = null;
public PlaceholderFragment() {
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_quiz, container, false);
mTrueButton = (Button) rootView.findViewById(R.id.true_button);
System.out.println(button);
return rootView;
}
}
另外一种方法是:如果熟悉Activity的生命周期的人可以知道:onCreate调用的时候其实还没构造对应的布局对象,因此不能在onCreate函数中获取控件,但可以在onStart函数中获取
@Override
protected void onStart() {
super.onStart();
mTrueButton = (Button)findViewById(R.id.true_button);
mTrueButton.setOnClickListener(new android.view.View.OnClickListener(){
public void onClick(android.view.View v) {
//TODO...
}
});
}
本回答被网友采纳
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询