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 extends View> 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 extends View> 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一點,但是看到別人的優秀程式碼,感覺其實要不要解耦不取決於程式碼的長短,而取決於具體的功能實現是否需要,這個還是需要經驗的積累吧。
這麼簡單的問題搞了一下午,真的是被自己蠢哭了。