今天要聊的東西其實很雜...
我今天想講的東西除了一方面是NumberPicker的使用介紹之外
一方面我也是想講一講"回調"這個東西
這是大陸的翻譯,又稱為接口
簡單來說就是把你在其他Java檔案中所做的運算結果回傳到主要的Java檔案中的一個作法
至於更詳細的解釋後面會有
那麼來看一下今天的範例
我在畫面中寫了一個AlertDialog的時間選擇器
然後在這個AlertDialog中放了三個NumberPicker
最後按下"確定"的按鈕後將三個NumberPicker所選到的數字統合後,顯示在螢幕中間
那麼,GitHub在此,我們開始吧
->https://github.com/thumbb13555/NumberPickerAndInterface_Demo
1. 首先...這倒底是在解決什麼問題?
對,你他喵的看了這麼多廢話,所以我到底是要解決什麼問題?( ´_ゝ`)
首先,這是一個算是很新手向的問題
很多老手都表示:
這這麼簡單,幹嘛講?(;・∀・)
其實對新手而言,我們看到老手們的程式都有好多好多個java檔案,看到這麼多抽象類別、介面interface檔案,還有好多好多資料夾
看都看昏了,根本就搞不清楚你們在寫些什麼
那今天我想提出來說的,就是在介面interface的這個部分
好,那麼我們蔡逼八們學到了一個階層,就發現一件事
你他喵的,我怎麼覺得程式越來越亂,要找到一個指定功能明明是自己寫的,卻找不到?(╯=▃=)╯︵┻━┻
然後冒出十萬個為什麼,以及百萬個J3小
所以今天的重點就是要來學著把程式"模組化"
其實模組化這東西,其實新手們每天都在用
像是你拉出一個TextView、一個按鈕
這些都是那些Googler們努力幫你造積木所造出的結果
而你就是把它寫好的積木拿出來用罷了
也因此,今天就帶你來聊聊關於元件模組化這個問題
先看下圖
這張圖有兩個Java檔案,一個是主要檔案MainActivity.java
另一個是TimePickerDialog.java的部分
來講講TimePicker這個檔案
這個檔案就包含了所有跟彈出來的時間選擇器有關的功能
而最後按下確定後,在選擇器中所取到的必要內容就會透過上面所述的接口把值傳回MainActivity.java
像是以下這張圖
所以...這樣做有什麼好處?
天哪,好處可多了
首先,善用模組化,可以讓你的程式更好讀,也更好維護
客戶只要說他操作到哪裡閃退,就知道哪個模組出錯了
二、雖然例子只是一個開啟AlertDialog的程式,程式碼不多
但是,如果今天是要寫一個數學模組呢?
又或者更複雜?
程式碼動不動500行?
如果都寫在MainActivity或是主要控制的話,不就會把程式塞到2、3000行?
基於以上理由,這就是你要把這篇文章看完的原因
所以我繼續往下吧!
2. 總之,先來畫介面吧
恩,如題(´∀`)
重點不在介面,所以直接給你就好
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <Button android:id="@+id/button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="取得時間" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <TextView android:id="@+id/textView_Respond" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="24dp" android:text="TextView" android:textAppearance="@style/TextAppearance.AppCompat.Large" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/button" /> </androidx.constraintlayout.widget.ConstraintLayout>
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="10dp"> <TextView android:id="@+id/textView2" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:text="秒" android:textAppearance="@style/TextAppearance.AppCompat.Large" app:layout_constraintBottom_toTopOf="@+id/numberPicker_M" app:layout_constraintEnd_toEndOf="@+id/numberPicker_S" app:layout_constraintStart_toStartOf="@+id/numberPicker_S" app:layout_constraintTop_toTopOf="parent" /> <NumberPicker android:id="@+id/numberPicker_S" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toEndOf="@+id/numberPicker_M" /> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:text="分" android:textAppearance="@style/TextAppearance.AppCompat.Large" app:layout_constraintBottom_toTopOf="@+id/numberPicker_M" app:layout_constraintEnd_toEndOf="@+id/numberPicker_M" app:layout_constraintStart_toStartOf="@+id/numberPicker_M" app:layout_constraintTop_toTopOf="parent" /> <NumberPicker android:id="@+id/numberPicker_H" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/numberPicker_M" app:layout_constraintStart_toStartOf="parent" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:text="時" android:textAppearance="@style/TextAppearance.AppCompat.Large" app:layout_constraintBottom_toTopOf="@+id/numberPicker_M" app:layout_constraintEnd_toEndOf="@+id/numberPicker_H" app:layout_constraintStart_toStartOf="@+id/numberPicker_H" app:layout_constraintTop_toTopOf="parent" /> <NumberPicker android:id="@+id/numberPicker_M" android:layout_width="wrap_content" android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintHorizontal_bias="0.498" app:layout_constraintStart_toStartOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
3. 先把模組寫好吧(TimePickerDialog)
首先第一步是先建立class
滑鼠右鍵->New->Java Class
然後,PO給你全部程式
class TimePickerDialog { private Activity activity; /**使InterFace可以被類別使用*/ OnDialogRespond onDialogRespond; public TimePickerDialog(Activity activity) { this.activity = activity; } public void showDialog() { /**關於AlertDialog相關的設置請參考這篇文章: * https://thumbb13555.pixnet.net/blog/post/310777160*/ AlertDialog.Builder mBuilder = new AlertDialog.Builder(activity); View view = LayoutInflater.from(activity).inflate(R.layout.number_picker_dialog, null); mBuilder.setView(view); mBuilder.setPositiveButton("確定",null); mBuilder.setNegativeButton("取消",null); AlertDialog dialog = mBuilder.create(); /**這裡是設置NumberPicker相關*/ NumberPicker npHour, npMin, npSec; npHour = view.findViewById(R.id.numberPicker_H); npMin = view.findViewById(R.id.numberPicker_M); npSec = view.findViewById(R.id.numberPicker_S); /**取得現在時間*/ Date date = new Date(); /**設置NumberPicker的最大、最小以及NumberPicker現在要顯示的內容*/ npHour.setMaxValue(23); npHour.setMinValue(0); npHour.setValue(Integer.parseInt(new SimpleDateFormat("HH").format(date))); npMin.setMaxValue(59); npMin.setMinValue(0); npMin.setValue(Integer.parseInt(new SimpleDateFormat("mm").format(date))); npSec.setMaxValue(59); npSec.setMinValue(0); npSec.setValue(Integer.parseInt(new SimpleDateFormat("ss").format(date))); dialog.show(); dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener((v -> { /**格式化字串*/ String s = String.format("%02d:%02d:%02d" , npHour.getValue(), npMin.getValue() ,npSec.getValue()); /**這邊將值放進OnDialogRespond中*/ onDialogRespond.onRespond(s); dialog.dismiss(); })); dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setOnClickListener((v -> { dialog.dismiss(); })); } /**設置Interface,使取到的直可以被回傳*/ interface OnDialogRespond{ void onRespond(String selected); } }
要設置Interface是有順序的,要先寫下面橘色底的部分
再來是寫上方粉色底的部分
完成設置後,再將綠色底的部分寫在希望他回傳值的地方就完成囉!
此外,請注目這邊
interface OnDialogRespond{ void onRespond(String selected); }
一個interface是可以有很多的回調的
像是也可以這項寫
interface OnDialogRespond{ void onRespond(String selected); void onCancel(int flag,String selected); }
這樣寫的話,稍後在MainActivity的回調就有兩個囉!
4. 把模組套到MainActivity的功能內吧
直接給!一目瞭然!
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); /**開啟模組*/ TimePickerDialog dialog = new TimePickerDialog(this); Button btShow = findViewById(R.id.button); TextView tvRes = findViewById(R.id.textView_Respond); btShow.setOnClickListener(v -> { dialog.showDialog(); }); /**這邊取得自己所設置之模組回調*/ dialog.onDialogRespond = new TimePickerDialog.OnDialogRespond() { @Override public void onRespond(String selected) { tvRes.setText(selected); } }; } }
步驟講解一下
1. 啟用模組
TimePickerDialog dialog = new TimePickerDialog(this);
2. 設置顯示Dialog
btShow.setOnClickListener(v -> { dialog.showDialog(); });
3.取得在Dialog中選取到的數值
/**這邊取得自己所設置之模組回調*/ dialog.onDialogRespond = new TimePickerDialog.OnDialogRespond() { @Override public void onRespond(String selected) { tvRes.setText(selected); } };
此外如果前面有設置兩個回調的話,OnDialogRespond就會有兩個@Override喔!
結語
搞了半天其實也沒什麼講NumberPicker哈哈哈哈哈哈
不過回調這個部分倒是講得不少
倒不如說我整篇的用意介紹那三行程式而已XDDDDDDDD
嚴肅講,其實我會講這個有個很大的原因
我發現,這個明明那~~~~麼的重要
可是我以前在學習的時候卻沒有任何一本書把這個東西特別拿出來講((也許是我書看太少!?
最近八月,我遇到了很多正在跟專題搏鬥的大學生
有蠻多人會發Email給我向我問問題,有的還會請我幫他看錯XD
通常大部分的人錯誤幾乎可說是一目瞭然,一看就知道忘了加什麼
但也從中發現到其實很多人的本質不是不會寫Android
是不會寫Java啊!(╯=▃=)╯︵┻━┻
喔,我是很樂意幫忙看程式的,所以還是可以繼續問我問題喔(・ωー)~☆
畢竟未來我想走教學路線~
回到上面的話題,其實我發現學生不會寫Java的好多
Java四大特性
多型、繼承、抽象、封裝
這些就算寫不出來,至少也要會看會比較好
尤其是Android本身的組件都是層層的繼承發展出來的
封裝更是寫出漂亮程式碼的關鍵
抽象可以幫助你少寫很多很多程式碼
多型更能讓你的程式邏輯更為清楚
哎呀,囉唆了:D
總之~
留言列表