Android開發:getViewById返回null的原因定位,androidgetviewbyid

來源:互聯網
上載者:User

Android開發:getViewById返回null的原因定位,androidgetviewbyid

      最近在研究開發一些基於Android的App,遇到了一些問題,其中一個比較關鍵的是在Activity中的onCreate()方法中擷取Button對象,代碼大概如下:

 

private Button mTrueButton;

@Override

public void onCreate(Bundle savedInstanceState){

   super.onCreate(savedInstanceState);

   setContentView(R.layout.activity_quiz);

 

   mTrueButton = (Button) getViewById(R.id.true_button);

   mTrueButton.setOnClickListener(…);

 

}

 

該代碼是根據一本android的編程指南進行修改的,但意想不到的是,一執行,app提示系統錯誤,終止運行,通過debug跟蹤發現:mTrueButton為null,系統執行到mTrueButton.setOnclickListener拋出java.lang.NullPointerException,很明顯,此時調用getViewById無法擷取到Button這個View對象,於是開始網上搜尋資料,認為可能的原因是下面幾個:

一,調用順序不當導致的異常

持這種觀點的主要原因是getViewById的調用放到了setContentView之前,如下:

super.onCreate(savedInstanceState);

mTrueButton = (Button)getViewById(R.id.true_button);

setContentView(R.layout.activity_quiz);

 

理由是:當activity 調用 setContentView() 時,android 才會去繪製 layout 上的各個元素,並為其分配記憶體。只有 分配了記憶體以後,才能繼續執行 ,findViewById(); 才能得到引用,不然得到Null 參考,Null 參考意味著,後面使用相應變數時就會發生訪問的對象不存在的問題。

而且當Activity重新setContentView()以後,那些之前繪製的控制項,記憶體都被滅掉了。

所以,若是通過setContentView 來達到畫面切換目的的,要注意重新繪製以後重新取得引用

 

 

二,getViewById的內容物件不匹配

這種方式讓筆者想到Javascript中的document.getElementById,兩者具有非常高的相似性,getElementById的調用需要指定對應的document對象,表示從該document對象擷取元素,同理,Android中的getViewById的完整調用是View.getViewById,因此需要關注該方法預設的context對象,一般是this,即當前的Activity,但有時候可能不是這樣,如:

 

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異常

 

三,開發工具Eclipse導致的問題

假定在自定的Adapter的getView方法中有類似如下的代碼:

 

View rowview = (View)inflater.inflate(R.layout.rowview, parent, false);

 

TextView tv_contact_id =(TextView)rowview.findViewById(R.id.tv_contact_id);

 

TextView tv_contactname =(TextView)rowview.findViewById(R.id.tv_contactname);

 

有時候居然也會發現rowview非空,但tv_contact_id和tv_contactname都是null!仔細看代碼,怎麼也看不出錯誤來。到底是什麼原因造成的呢?答案是Eclipse造成的,要解決這個問題,需要這個項目clean一次(Project菜單 -> Clean子功能表),這樣就OK了。

 

 

四,新版本SDK不能在onCreate方法中調用了-筆者的問題原因在此。

重要的環境交代:剛學Android,在官網下載的新版的ADT以及新版的SDK在新版的IDE(ADT)建立項目時如果你的最小版本(minimumrequiredSDK)要支援4.0以下版,並且目標版本為(4.0+),那麼此時IDE會為你建立一個相容包(appcompat_v7)建立項目後,這個時候在產生的項目主Activity不是以前的那種繼承的Activity,而是繼承的ActionBarActivity。

   此時,如果你仍然用舊的辦法在onCreate調用getViewById,那麼會返回null,原因是:在新的layout檔案不是存放在預設的(res/layout/activity_quiz.xml)檔案中,而是存放在(res/layout/fragment_quiz.xml)檔案中。所以要在fragment_quiz.xml去找對應的ID才會找到,而新的IDE產生的程式碼中載入(fragment_quiz.xml)檔案是在一個內部類載入的,所以一種方法是:我們可以在內部類載入處來得到Button。

    /**

     * A placeholder fragment containing a simple view.

     */

    public static class PlaceholderFragment extends Fragment {

        

        View rootView = null;

        public PlaceholderFragment() {

        }

 

        @Override

        public View onCreateView(LayoutInflater inflater, ViewGroup container,

                Bundle savedInstanceState) {

            rootView = inflater.inflate(R.layout.fragment_quiz, container, false);

            mTrueButton = (Button) rootView.findViewById(R.id.true_button);

          System.out.println(button);

            return rootView;

        }

      

    }

      另外一種方法是:如果熟悉Activity的生命週期的人可以知道:onCreate調用的時候其實還沒構造對應的布局對象,因此不能在onCreate函數中擷取控制項,但可以在onStart函數中擷取:(筆者的方案就是在onStart方法中擷取的)

@Override
protected void onStart() {
      super.onStart();
      mTrueButton = (Button)findViewById(R.id.true_button);
      mTrueButton.setOnClickListener(new android.view.View.OnClickListener(){
          public void onClick(android.view.View v) {
             //TODO...
          }
      });
}

 

 

 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.