摘要:
加载Android布局文件时出现错误:
java.lang.NullPointerException: Attempt to invoke virtual method '........' on a null object reference
出错原因可能是未能在正确的View环境下使用findViewById()方法。
Android新手,啥都不懂。
做了一个ListView,想实现功能:点击Item,弹出一个对话框,对话框中包含一个ImageView,代码如下:
ImageView photo;
Bitmap bitmap = BitmapFactory.decodeStream(
getContext().getContentResolver().openInputStream(uri));
ImageView photo = getView().findViewById(R.id.photo);
photo.setImageBitmap(bitmap);
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
builder.setView(R.id.dialog);
/*定义其他按键*/
AlertDialog dialog = builder.create();
dialog.show();
为对话框新建了一个Layout布局文件,这个R.id.photo就放在这个文件中。
然而运行时老是报错:java.lang.NullPointerException: Attempt to invoke virtual method '........' on a null object reference
问题的原因是photo没有正确初始化。
想了一下,明明我都关联好了,编译也没问题,应该能正确初始化的。
然后想到了findViewById()的原理,之前都是乱拿来用的。通过这个错误我意识到可能是findViewById()设置不当。
一般用findViewById()都是在Activity的OnCreate()方法里面,例如:
button = (Button)findViewById(R.id.button);
这里的findViewById()函数来自于Activity类:
public T findViewById(@IdRes int id) {
return getWindow().findViewById(id);
}
我们在Fragment中使用findViewById()时候,需要创建Fragment的View对象,然后调用View对象的findViewById()方法。
View v = inflater.inflate(R.layout.fragment, container, false);
listView = v.findViewById(R.id.list_view);
其中View类中findViewById()方法如下:
@Nullable
public final T findViewById(@IdRes int id) {
if (id == NO_ID) {
return null;
}
return findViewTraversal(id);
}
具体我就不研究了,(反正我的水平也搞不懂)
我出现上面错误的原因就是没有搞清楚该用哪一个findViewById()。因为调用getView()得到的应该是当前显示的View,而我这里要显示的是一个Dialog对话框专用的新的布局文件,因此不能用当前的View对象来初始化ImageView。
解决办法就是新建一个类继承Dialog类,在该类中定义要显示的元素,并且重新OnCreate()方法:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LayoutInflater inflater = (LayoutInflater) mContext
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
View layout = inflater.inflate(R.layout.photo_dialog, null);
photo = layout.findViewById(R.id.photo);
try{
Bitmap bitmap = BitmapFactory.decodeStream(
getContext().getContentResolver().openInputStream(uri));
photo.setImageBitmap(bitmap);
}catch (Exception e){
e.printStackTrace();
}
this.setContentView(layout);
}
}
原来的Fragment中只需要简单的两句:
MyDialog myDialog = new MyDialog(getContext());
myDialog.show();
总之就是要创建一个复杂的Dialog,最好重写Dialog方法,别把乱七八糟的东西都挤到原来的类里。
作为一个初学者,有时候吧,想把代码写得OOP一点,但是看到别人的优秀代码,感觉其实要不要解耦不取决于代码的长短,而取决于具体的功能实现是否需要,这个还是需要经验的积累吧。
这么简单的问题搞了一下午,真的是被自己蠢哭了。