Garmin アプリ開発(5) クラス構造
公式のサンプル
おおよそこういうクラス構造でした。上に並んでいるSDKのクラスを派生するSampleXXX という名前の4つのクラスで出来ています。
Menuが要らなければ、最小3つのクラスでアプリが作れます。
公式サンプルの課題
作りたいアルゴリズム(いわゆるドメイン知識とかビジネスロジック)が、主に「SampleView」に入り込んでいる構造です。簡単なうちはこれでもいいですが、少し複雑なものは別のクラスに出した方がいいです。
自作アプリ
ということで、2つクラスを足して5個のクラスでアプリを作ります。
AdditionalTimeStopwathApp アプリケーション本体、全体を生成する
AdditionalTimeDelegate キー入力
AdditionalTimeView 画面表示
これらの3つのクラスはサンプルと同じくGarminのSDKの派生クラスになってます。この派生クラスはテストしにくいので、なるべくシンプルに保つように作っていきます
AdditionalTimeHandler 自作の入力と表示をハンドリングするクラス
StopWatch ストップウォッチクラス
真ん中下段にあるこの2つのクラスを足します。自分が作りたい複雑なロジックはここに入れていくことにします。
AdditionalTimeStopwathApp
SDKのAppBaseの派生クラスで、アプリが起動したときに最初に実行されます。source code
公式: https://developer.garmin.com/connect-iq/core-topics/the-application-object/
詳細なライフサイクルは公式の解説を参照するとして、ここから自分のクラスを生成する必要があります。
ここでは、自作クラスAdditionalTimeHandlerの生成を追加し、依存関係にあるクラスをDependency Injection(依存関係の外部からの注入)の考え方で、引数で与えています。
AdditionalTimeHandler(view); ←HandlerはViewに依存している
AdditionalTimeDelegate(handler): ←Delegateはhandlerに依存している
AddtionalTimeView
レイアウトされたUIパーツに文字列を設定したり、表示を切り替えたりするクラスです。source code
公式: https://developer.garmin.com/connect-iq/core-topics/user-interface/
詳細なViewクラスのライフサイクルは公式参照ですが、主なものはこちらです
View.onShow()
: 表示されたとき
View.onLayout(dc)
: レイアウトがロードされたとき
View.onUpdate()
: 表示の更新
View.onHide()
: 表示が終わった時
アプリの表示が終わるなどの重要イベントに関してはアプリ全体の動きが変わるのでAddtionalTimeHandlerに伝える必要があります。
そのためHandler → View間でcallbackの仕組みで、依存関係の逆転(DIP: dependency inversion principle)を行ってます
Handler側
//! Constructor
public function initialize(view as AdditionalTimeView) {
self._view = view;
self._stopwatch = new StopWatch();
self._viewtimer = new Timer.Timer();
view.Register(method(:onShow), method(:onHide)); // ← コールバック登録
self._lastvibrated = System.getTimer();
}
View側
//コールバック呼び出し
function onHide() as Void {
if(self._onHideCallback){
self._onHideCallback.invoke();
}
}
//コールバック登録
public function Register(onShowCallback as Method, onHideCallback as Method){
self._onShowCallback = onShowCallback;
self._onHideCallback = onHideCallback;
}
これで依存関係とは反対方向の呼び出しが可能になります
AddtionalTimeDelegate
キー入力をハンドリングするクラスです source code
公式: https://developer.garmin.com/connect-iq/core-topics/input-handling/
onKey()
onKeyPressed()
onKeyReleased()
このアプリでは上記3つだけハンドリングしています。
Pressed/Releasedはボタン長押し判定が必要な場合にハンドリングします