Android开发中出现Attempt to invoke virtual method...on a null object reference

摘要:

加载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);

其中(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一点,但是看到别人的优秀代码,感觉其实要不要解耦不取决于代码的长短,而取决于具体的功能实现是否需要,这个还是需要经验的积累吧。

这么简单的问题搞了一下午,真的是被自己蠢哭了。


你可能感兴趣的:(Android)