LoginSignup
18
19

More than 5 years have passed since last update.

ステートマシンのすすめ - Androidで位置情報を使う

Last updated at Posted at 2015-04-12

はじめに

私たちのチームでは2年ほど前からAndroidやiOSで設計をするときにステートマシンを使っているのですが、界隈の方々と話していていてあんまり聞いたことがないので、ちょっと使い方どころなどを紹介してみたいと思います。

やりたいことをイメージする

題材として位置情報を取得して画面を更新するいうシーンを考えてみます。

位置情報を取得するクラス(LocationClient, GoogleApiClient)を見てみると

基本的には、

  1. Activity(Fragment)のonStartでサービスに接続する
  2. 接続ができたら位置情報をリクエストする
  3. 取得した位置情報をもとに画面を更新する

という流れになると思います。

ここまでは普通ですね?

まずは使ってみる

下調べができたので、ステートマシンを作ります。SMCという自動でコード生成してくれる便利なツール( http://smc.sourceforge.net/
)があるので、これを使いましょう。

%package com.example.smc.location
%fsmclass LocationControllerStateMachine
%class LocationControllerAction

%start LocationControllerStateMap::STOPPED

%map LocationControllerStateMap
%%
STOPPED
{
    start CONNECTING {}
}

CONNECTING
    Entry { connect(); }
{
    notifyConnected UPDATING {}
}

UPDATING
    Entry { updateLocation(); }
{
    locationChanged READY { onLocationChanged(); } 
}

READY
    Entry { onReady(); }
{
}

Default
{
    Default nil {}
}
%%

png (3).png

隠れた仕様を作り込む

あとは、エラーの時とか、途中で画面遷移しちゃった時とか考慮すれば大丈夫なはずです。

画面がバックグラウンドに回った時のイベント(stop), エラー(notifyError)を追加してみます。

%package com.example.smc.location
%fsmclass LocationControllerStateMachine
%class LocationControllerAction

%start LocationControllerStateMap::STOPPED

%map LocationControllerStateMap
%%
STOPPED
    Entry { disconnect(); }
{
    start CONNECTING {}
    stop nil {}
    notifyError nil {}
}

CONNECTING
    Entry { connect(); }
{
    notifyConnected UPDATING {}
}

UPDATING
    Entry { updateLocation(); }
{
    locationChanged READY { onLocationChanged(); } 
}

READY
{
     updateLocation UPDATING {}
}

NO_CONNECTION
{
     notifyError nil {}
}

Default
{
    stop STOPPED {}  /* onStopが呼ばれたことを示すイベント */
    notifyError NO_CONNECTION {}
    Default nil {}
}
%%

png (1).png

機能追加も簡単

位置情報は取得するのに時間がかかることもあります。タイマーで時間を計りタイムアウトするようにしてみましょう。

%package com.example.smc.location
%fsmclass LocationControllerStateMachine
%class LocationControllerAction

%start LocationControllerStateMap::STOPPED

%map LocationControllerStateMap
%%
STOPPED
    Entry { disconnect(); }
{
    start CONNECTING {}
    stop nil {}
    notifyError nil {}
}

CONNECTING
    Entry { connect(); }
{
    notifyConnected UPDATING {}
}

UPDATING
    Entry { setTimer(); updateLocation(); }  /* タイマー開始 */
    Exit { clearTimer(); }  /* タイマー止める */
{
    locationChanged READY { onLocationChanged(); } 
    notifyTimeout READY { onTimeout(); }  /* ここにタイマー追加 */
}

READY
{
     updateLocation UPDATING {}
}

NO_CONNECTION
{
     notifyError nil {}
}

Default
{
    stop STOPPED {}
    notifyError NO_CONNECTION {}
    Default nil {}
}
%%

png (2).png

おわりに

こんな感じで、さくさくと設計を進めることができます。

また、Androidを想定して作ってみましたが、そんなにOS依存なところはありませんので、iOSなど他のプラットホームにも簡単に移植できます。

自動で図を描いてくれるツールなどもありますので、他の人から引き継いだステートマシンも容易に理解できます。(たくさんのフラグで制御されている実装だとプログラムの流れを読み解いていかないといけない。)

こんな感じで便利なので、設計にはステートマシンがおすすめです。

18
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
18
19