原來的程式片段是這樣的
1 @Override 2 public void onCreate(Bundle savedInstanceState) { 3 super.onCreate(savedInstanceState); 4 setContentView(R.layout.main); 5 6 //Listen for button clicks 7 Button button = (Button) findViewById(R.id.submit); 8 button.setOnClickListener(calcBMI); 9 }上面的程式片段中,包含了所有 Android 程式共用的標準內容, 整個程式的大致架構在前面章節中已經講解過,現在我們從中取出我們感興趣的部分來討論:
Button button = (Button) findViewById(R.id.submit); button.setOnClickListener(calcBMI);在第7行我們看到一段程式碼來宣告按鈕物件,與針對該按鈕物件作動作的程式碼。 button.setOnClickListener 程式碼的意義是指定一個函式,來負責處理"按下"這個"按鈕"後的動作。
我們可以想像,在同一個畫面中,多加入一些按鈕與欄位後,"onCreate" 這段程式將變得壅腫,我們來試著先對此稍作修改:
首先,我們可以套用 MVC 模式,將宣告介面元件(按鈕、數字欄位)、指定負責函式等動作抽取出來,將 onCreate 函式改寫如下
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViews(); setListeners(); }接著我們將宣告介面元件的部份寫成一個獨立的「findViews」函式:
private Button calcbutton; private EditText fieldheight; private EditText fieldweight; private void findViews() { calcbutton = (Button) findViewById(R.id.submit); fieldheight = (EditText) findViewById(R.id.height); fieldweight = (EditText) findViewById(R.id.weight); }順便將原本很沒個性的按鈕識別參數「button」改名成「calcbutton」,以後在程式中一看到「calcbutton」,就知道是一個按下後將開始處理計算工作的按鈕。
同樣地,我們也將指定特定動作(按按鈕)的負責函式獨立出來:
//Listen for button clicks private void setListeners() { calcbutton.setOnClickListener(calcBMI); }如此一來,我們就將程式邏輯與介面元件的宣告分離開來,達成我們重構的目的。
完整程式如下:
package com.demo.android.bmi; import java.text.DecimalFormat; import android.app.Activity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; public class Bmi extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findViews(); setListeners(); } private Button button_calc; private EditText field_height; private EditText field_weight; private TextView view_result; private TextView view_suggest; private void findViews() { button_calc = (Button) findViewById(R.id.submit); field_height = (EditText) findViewById(R.id.height); field_weight = (EditText) findViewById(R.id.weight); view_result = (TextView) findViewById(R.id.result); view_suggest = (TextView) findViewById(R.id.suggest); } //Listen for button clicks private void setListeners() { button_calc.setOnClickListener(calcBMI); } private Button.OnClickListener calcBMI = new Button.OnClickListener() { public void onClick(View v) { DecimalFormat nf = new DecimalFormat("0.0"); double height = Double.parseDouble(field_height.getText().toString())/100; double weight = Double.parseDouble(field_weight.getText().toString()); double BMI = weight / (height * height); //Present result view_result.setText(getText(R.string.bmi_result) + nf.format(BMI)); //Give health advice if(BMI>25){ view_suggest.setText(R.string.advice_heavy); }else if(BMI<20){ view_suggest.setText(R.string.advice_light); }else{ view_suggest.setText(R.string.advice_average); } } }; }同樣是「calcBMI」 函式,在完整程式中,改將「calcBMI」 函式從原本的「OnClickListener」宣告成 「Button.OnClickListener」。這個改變有什麼差別呢?
閱讀原本的程式碼,在匯入(import)的部分可以看到,「OnClickListener」是來自於「android.view.View.OnClickListener」函式:
import android.view.View.OnClickListener;改成 「Button.OnClickListener」後,「Button.OnClickListener」就變成來自於「android.widget.Button」中的「OnClickListener」函式,在查閱程式時,整個「Button」與「OnClickListener」之間的關係變得更清晰。
另外,我們偷偷將「OnClickListener」中其他會存取到的介面元件識別參數,也補進 findViews 宣告中:
private void findViews() { button_calc = (Button) findViewById(R.id.submit); field_height = (EditText) findViewById(R.id.height); field_weight = (EditText) findViewById(R.id.weight); view_result = (TextView) findViewById(R.id.result); view_suggest = (TextView) findViewById(R.id.suggest); }同時,我們也把識別參數的命名方法做了統一:按鈕的識別參數前加上 「button_」前綴,可輸入欄位的識別參數前加上 「field_」前綴,用作顯示的識別參數前則加上「view_」前綴。將變數名稱的命名方法統一有什麼好處呢? 好處在於以後不管是在命名新變數,或是閱讀程式碼時,都能以更快速度命名或理解變數的意義,讓程式變得更好讀。
我們也把原本在程式中直接寫進的字串
TextView result = (TextView) findViewById(R.id.result); result.setText("Your BMI is "+nf.format(BMI));改寫成
//Present result view_result.setText(getText(R.string.bmi_result) + nf.format(BMI));