【Debug-NullPointerException】findViewById(): Attempt to invoke ...on a null object reference
阿新 • • 發佈:2019-01-31
空指標異常很常見,也很好找,今天重構程式碼的時候,愣是報了一個很神奇的NullPointerException
java.lang.RuntimeException: Unable to start activity ComponentInfo{com...Activity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setOnClickListener(android.view.View$OnClickListener)' on a null object reference at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2315) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2375) at android.app.ActivityThread.access$900(ActivityThread.java:147) . . . Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.TextView.setOnClickListener(android.view.View$OnClickListener)' on a null object reference . .
所有的跡象都指向我繫結的控制元件為“null”,怎麼可能,我的控制元件都是老老實實地用【findViewById()】方法一個一個繫結的id,經檢查id沒錯,R檔案也沒錯,折騰半天突然想到,重構程式碼時為了讓程式碼結構清晰,給所有的Activity加了一個父類BaseActivity,並在【onCreate();】方法中整了一個“initViews()”方法用來初始化一些東西。
BaseActivity的程式碼結構是:
public abstract class BaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_base); initViews(); } /** 初始化檢視 **/ protected abstract void initViews(); }
這樣的好處是讓子Activity在繼承的時候都要複寫父類Activity的抽象方法“initViews()”,使得子Activity的【onCreate();】方法不至於太臃腫龐大。
但是會產生一個問題,在子Activity中,【initViews()】部分會先於【onCreate()】部分執行(如下)
這就導致【findViewById()】部分會先於【setContentView(R.layout.activity_main);】部分執行,這是不對的。
子Activity的結構:
public class MainActivity extends BaseActivity { private TextView textView ; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 罪魁禍首,錯誤位置 log.d("TAG", "本程式碼塊中的程式碼的執行順序為:2222222222222222"); } @Override protected void initViews() { log.d("TAG", "本程式碼塊中的程式碼的執行順序為:1111111111111111"); // 【注意】“setContentView”的位置放在onCreate()中會導致執行的先後順序出錯而報空指標錯誤。 setContentView(R.layout.activity_main); // 正確位置 // 繫結控制元件 textView = (TextView)findViewById(R.id.tv_text); textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //... } }); }
修正錯誤:
方法:按照上述程式碼,把【setContentView(R.layout.activity_main);】這一行從【onCreate()】中移到【initViews()】中。