【求助】如何自制后庭玩具ListView后在MainActivity中findViewById后强转成自己写的ListView类时报ClassCastExection

7627人阅读
【android提高】(78)
你是不是经常遇到在fragment中调用findViewById方法寻找fragment布局文件中的控件返回null的现象。我之前也遇到了这个问题,虽然后来解决了,但是心中一直有疑惑,最近有时间停下来,结合别人的解答和自己的思考,对这个问题进行彻底的梳理。
二、使用getActivity().findViewById
1、getActivity的介绍
Fragment中有一个getActivity()的方法。返回与Fragment关联的Activity对象(通过该对象可以查找activity中的控件们(findViewById()))。当fragment生命周期结束并销毁时,getActivity()返回的会是null。onAttach和onDetach之间的其他生命周期方法都可以调用getActivity方法。
2、在Fragment的oncreateview()方法中使用
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//从数据库中得到黑名单的集合
super.onActivityCreated(savedInstanceState)
View view = inflater.inflate(R.layout.fragment_dark, container, false)
infoList = DbManager.getInstance().getDarkList()
listView = (ListView) getActivity().findViewById(R.id.dark)
adapter = new DarkAdapter(getActivity(), infoList)
listView.setAdapter(adapter)
registerForContextMenu(listView)
return view
空指针异常
因为onCreateView时,fragment已经和activity绑定了,所以说getActivity是有值的,但是我们返回值为空,说明在activity的子控件中找不到fragment的控件----&说明fragment的控件还没有加到activity中。
为什么呢?原因如下:
View view = inflater.inflate(R.layout.fragment_dark, container, false);
该方法的第二个参数的意思是:root
Optional view to be the parent of the generated hierarchy (if attachToRoot is true), or else simply an object that provides a set of LayoutParams values for root of the returned hierarchy (if attachToRoot is false.)
该方法的第三个参数的意思是: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.
在本代码中第三个参数为false,说明当前fragment的布局文件并没有被加到activity的布局中,所以你当然无法在activity中找到fragment的组件了。但是一旦onCreateView执行完了,系统就把fragment的布局文件加入到activity的布局文件中了。所以只要在onCreateView方法之后,我们通过getActivity().findViewById都是可以得到fragment的子控件的。所以下面的3结果就是对的。
有的人可能有疑问了:如果我们把false改为true,这样是不是就可以在onCreateView使用getActivity().findViewById找到fragment的子控件了。事实上,这样做会产生异常,你把fragment的布局文件加到activity的布局一次,但是当onCreateView方法执行完之后,返回View,系统又执行了一次把fragment的布局文件加到activity的布局,就会产生错误。
3、在Fragment的onstart()方法中使用
public void onStart() {
super.onStart();
infoList = DbManager.getInstance().getDarkList();
listView = (ListView) getActivity().findViewById(R.id.dark);
adapter = new DarkAdapter(getActivity(), infoList);
listView.setAdapter(adapter);
registerForContextMenu(listView);
理解了2的分析,这里就没有问题了。
三、使用getview().findViewById
1、getview的介绍
开发文档的解释:
Get the root view for the fragment’s layout (the one returned by onCreateView(LayoutInflater, ViewGroup, Bundle)), if provided.
The fragment’s root view, or null if it has no layout.
2、在Fragment的oncreateview()方法中使用
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//从数据库中得到黑名单的集合
super.onActivityCreated(savedInstanceState)
View view = inflater.inflate(R.layout.fragment_dark, container, false)
infoList = DbManager.getInstance().getDarkList()
listView = (ListView) getView().findViewById(R.id.dark)
adapter = new DarkAdapter(getActivity(), infoList)
listView.setAdapter(adapter)
registerForContextMenu(listView)
return view
空指针异常
我们看getView的方法解释:Get the root view for the fragment’s layout (the one returned by onCreateView(LayoutInflater, ViewGroup, Bundle)), if provided.而现在,我们在onCreateView内部使用getView,onCreateView还没有执行完,getView自然无法得到onCreateView的返回值。因此产生空指针异常
3、在Fragment的onstart()方法中使用
public void onStart() {
super.onStart();
infoList = DbManager.getInstance().getDarkList();
listView = (ListView) getView().findViewById(R.id.dark);
adapter = new DarkAdapter(getActivity(), infoList);
listView.setAdapter(adapter);
registerForContextMenu(listView);
空指针异常
四、推荐的方式
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
//从数据库中得到黑名单的集合
super.onActivityCreated(savedInstanceState)
View view = inflater.inflate(R.layout.fragment_dark, container, false)
infoList = DbManager.getInstance().getDarkList()
listView = (ListView) view.findViewById(R.id.dark)
adapter = new DarkAdapter(getActivity(), infoList)
listView.setAdapter(adapter)
registerForContextMenu(listView)
return view
五、更多知识的讲解
1、findViewById
findViewById()是View对象的方法,先通过inflate()方法得到View,调用这个View对象的getViewById()方法,就能得到这个View树上的子View。
findViewById的完整写法是View.findViewById(),而不指定View时默认的是Context,因此当findViewById不是在context里执行时,要指定对应的View
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异常。
findViewById返回为null,原因是:find的View下面,没有包含对应的想要找的view,从而导致找不到,返回null。
常见的findViewById返回null的问题:在setContentView调用之前,调用了findViewById去找main布局中的界面元素lv_contactbook,那么所得到的lv一定是null。正确的做法是将上面代码中加粗的哪一行,挪至setContentView方法调用之后。
2、inflate方法与 findViewById 方法区别
inflate方法与 findViewById 方法区别 | LayoutInflater的inflate函数用法详解 :
inflate()和findViewById()函数的用法:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
○ 种一棵树最好的时间是十年前,其次是现在
○ 坚持输出,坚持书写,才可以持续成长
○ 所有美好事物的成长都是缓慢的
○ 既往不恋,未来不迎,当下不杂
○ 业精于勤,荒于嬉,行成于思,毁于随
○将军赶路 不追小兔
○不要拘泥于语言,同样也不要拘泥于行业,眼光放远一点
○ 如果某件事你做的不够好,不必介怀,因为以后的每一次每一天你都会做得越来越好
○ 此心不于事上磨,更于何处磨此心
○ 保持热情,保持求知欲
○ 千里之行,始于足下
○ 最怕你一生碌碌无为,还安慰自己平凡可贵。
○ 对于任何事,要保持自觉积极主动探索尝试。但是如果自己不积极认真地生活,不管得到什么样的回答都没有用。----解忧杂货店
访问:647266次
排名:千里之外
原创:286篇
转载:50篇
评论:113条
专业技能:
android, linux, Java, C/C++, Python, SQL, servlet&jsp, html
相关项目经验:
桌面应用,Android,Java web项目,Python web项目
实践输出平台:
(1)(9)(1)(2)(4)(6)(6)(62)(48)(54)(21)(13)(1)(37)(3)(2)(32)(15)(1)(2)(10)(6)您要找的页面不存在 - 简书
您要找的页面不存在
可能是因为您的链接地址有误、该文章已经被作者删除或转为私密状态。1962人阅读
effective android
一、Adapter写在哪并不是重点
ListView的Adapter应该写在Activity外面还是里面?
我想很多很多开发者估计都不知道这个问题。
而有部分人可能会嗤之以鼻,adapter写在外面和里面不都一样么?爱怎么写怎么写
这话没错,其实写在哪里都是没有问题的。
请别拍我板砖,我不是来搞笑的。
我先要说明一下我为什么要写这么一篇博客。
最近看了一些其他同时以前的项目,发现大多数项目的做法是建立一个package包专门存放Adapter类的,也有的人会嫌麻烦两个类切来切去,干脆都写在Activity中。
而我属于后者,我并不觉得adapter需要单独占用一个包,因为大多数时候他们并不能给其他Activity复用。
然而这两种方式都是可以的,看个人习惯或者团队做法了。
但有一点很关键,无论如何,adapter不能持有activity的引用!否则会出现内存泄漏的风险!
为什么呢? 因为adapter里面可能会做一些耗时操作,当finish activity时会因为被adapter持有引用而导致activity无法被回收,从而导致内存泄漏。
二、Adapter为什么写在Activity外面
上面也说了,adapter不能持有Activity的引用,否则会有内存泄漏的风险。
而Java中,非静态内部类对象是会隐式持有外部类引用的,也就是说adapter持有了activity的引用……
关于内部类可以看这篇博客:
所以就有将Adapter写在单独的一个包中的做法,估计很多开发者都不知道原来是这个原因,认为只是为了让Activity看起来更简洁。
然而我还想说的是,adapter写在外面也阻止不了蹩脚程序员(噗,其实我前段时间就是)想在adapter内持有Activity引用。因为很多时候adapter不可避免的需要和Activity交互,或者需要一个context对象
比如说这种情况……
需要点击某个Item中的Button,跳转到一个新的Activity的时候。
很多人会这么做……
public class MainActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listView = (ListView) findViewById(R.id.listView);
ExampleAdapter adapter = new ExampleAdapter(this);
listView.setAdapter(adapter);
public class ExampleAdapter extends BaseAdapter {
private Context mC
public ExampleAdapter(Context context) {
this.mContext =
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(mContext).inflate(R.layout.list_item, null);
TextView textView = (TextView) convertView.findViewById(R.id.text);
textView.setText(String.valueOf(position));
Button button = (Button) convertView.findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
mContext.startActivity(new Intent(mContext, SecondActivity.class));
return convertV
这种情况下adapter就持有了Activity引用了,如果我在adapter中进行耗时操作(比如加载图片之类的),并且finish Activity。
虽然此时Activity销毁了,但是GC也是无法回收的……而Activity占用的内存还是比较大的。
三、不持有Activity对象的情况下怎么和Activity交互
首先说明一种情况,有人会想着使用弱引用来保存Activity。
但我认为这是不好的做法,因为弱引用对象随时都有可能被回收,虽然可以判断是否为空不至于报空指针异常,但是会导致和Activity交互失败。用户体验肯定是不好的
在上main的例子中,想要和Activity交互还是有很多方式的。
首先我们来说一下inflate一个xml,完全可以使用parent的context,如下
然后button的点击跳转Activity,我们可以弄一个回调,如:
adapter构造中的context忘记删除了,别在意细节……反正没持有引用对吧
这样就可以在不持有activity的情况下愉快的交互了
四、说好的Adapter写在内部呢
别急,adapter写在Activity里面的话只需要加个static关键字就行了,其他和写在外面是一样的。
Adapter到底写在哪呢?
你怎么舒服怎么来就行了,千万小心不要导致内存泄漏就行,反正我是喜欢写里边,隐藏外部访问并且写起来舒服?(?-?)?
不止adapter,如果还写了的话也要写成静态的内部类哦
还有handler之类的~~~
最近都是上班敲代码,下班后也宿舍敲到12点,忙里偷闲写了这篇博客,感觉整个人都被掏空了啊啊啊啊啊啊啊啊啊啊。
今晚我决定要玩游戏!不敲代码了,我这是保护头发,小心中年谢顶
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:90816次
积分:1465
积分:1465
排名:千里之外
原创:29篇
评论:189条
(1)(1)(1)(1)(2)(3)(2)(2)(1)(4)(1)(2)(6)(2)(2)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'

参考资料

 

随机推荐