コマンド画面の実装

次に、コマンド画面の実装を説明します。

コマンド画面は、レイアウトファイル fragment_command.xml で定義されており、クラス内の実装と次のように結びついています。

Butter Knife の利用 で示したように、これらはアノテーションによって関連付けています。

public class CommandFragment extends Fragment {
  @BindView(R.id.checkBoxPowerOn) CheckBox mCheckBoxPowerOn;
  @BindView(R.id.textViewBrightness) TextView mTextViewBrightness;
  @BindView(R.id.seekBarBrightness) SeekBar mSeekBarBrightness;
  @BindView(R.id.textViewCommandResult) TextView mCommandResult;
  @BindView(R.id.textViewStatePower) TextView mTextViewStatePower;
  @BindView(R.id.textViewStateBrightness) TextView mTextViewStateBrightness;
  @BindView(R.id.textViewMotion) TextView mTextViewStateMotion;

  @Override
  public View onCreateView(LayoutInflater inflater, ViewGroup container,
                           Bundle savedInstanceState) {
    View view = inflater.inflate(R.layout.fragment_command, container, false);
    mButterknifeUnbunder = ButterKnife.bind(this, view);
    ......
    return view;
  }

  @OnClick(R.id.buttonSend)
  void onSendCommand() {
    ......
  }

  @OnClick(R.id.buttonRefresh)
  void onRefreshState() {
    ......
  }
}

このページでは、SEND COMMAND ボタンによるコマンドの送信処理と REFRESH STATE ボタンによるステートの取得処理について解説します。

なお、onCreateView() での画面の初期化方法や、SeekBar を操作したときに OnSeekBarChangeListener 経由でつまみの位置を数値化して表示する処理は、Android アプリの一般的なの処理のため説明を省略します。

コマンドの送信処理

コマンド画面に切り替わった後、SEND COMMAND ボタンをクリックすると、画面で設定されたパラメーターに従って、コマンドが Thing に送信されます。

ここでは以下の処理を行っています。

@OnClick(R.id.buttonSend)
void onSendCommand() {
  mCommandResult.setText("");

  List<Action> actions = new ArrayList<>();

  TurnPower action1 = new TurnPower();
  action1.power = mCheckBoxPowerOn.isChecked();
  actions.add(action1);

  if (action1.power) {
    SetBrightness action2 = new SetBrightness();
    action2.brightness = mSeekBarBrightness.getProgress();
    actions.add(action2);
  }

  PromiseAPIWrapper api = new PromiseAPIWrapper(mAdm, mApi);
  mAdm.when(api.postNewCommand(HelloThingIF.SCHEMA_NAME, HelloThingIF.SCHEMA_VERSION, actions)
  ).then(new DoneCallback<Command>() {
    @Override
    public void onDone(Command command) {
      String commandID = command.getCommandID();
      showToast("The command has been sent: " + commandID);
    }
  }).fail(new FailCallback<Throwable>() {
    @Override
    public void onFail(final Throwable tr) {
      showToast("Failed to send the command: " + tr.getLocalizedMessage());
    }
  });
}

はじめに、mCommandResult のコマンドリザルト表示領域をクリアします。この後送信するコマンドの結果を反映する前に、受信済みの結果を一旦リセットしています。

次に、送信するコマンドを構成するアクションの配列を actions に用意します。TurnPower と SetBrightness はいずれも Action クラスのサブクラスであるため、List<Action> が型名です。

TurnPower アクションでは、power にチェックボックス Power ON の値を読み込んで設定します。SetBrightness アクションでは、brightness に SeekBar の明るさの値を読み込んで設定します。SetBrightness アクションは、電源をオンにするときだけ設定します。

必要なアクションを actions に設定後、postNewCommand() メソッドを呼び出します。

  • 成功時は onDone() メソッドに実行したコマンドが渡されます。ここではデバッグ用に、トーストでコマンド ID を表示します。
  • 失敗時は onFail() メソッドが呼び出されます。ここではトーストでエラーメッセージを出力します。

ここでは電源と明るさを操作する 2 つのアクションを、それぞれ 1 個ずつのパラメーターで定義していますが、実際のプログラムではソリューションの仕様に合わせて複雑なコマンドを扱うことができます。独自のコマンドを定義する際、アクションを表現する Java のインスタンスが JSON に変換できることが要件です。

PromiseAPIWrapper での postNewCommand() の実装は以下のとおりです。ThingIFAPI の postNewCommand() を作業スレッドから呼び出す処理が Promise を使って記述されています。

public Promise<Command, Throwable, Void> postNewCommand(final String schemaName, final int schemaVersion, final List<Action> actions) {
  return mAdm.when(new DeferredAsyncTask<Void, Void, Command>() {
    @Override
    protected Command doInBackgroundSafe(Void... voids) throws Exception {
      return mApi.postNewCommand(schemaName, schemaVersion, actions);
    }
  });
}

ステートの取得処理

REFRESH STATE ボタンをクリックすると、Thing Interaction Framework から最新のステートを取得して画面に反映します。

ここでは以下の処理を行っています。

@OnClick(R.id.buttonRefresh)
void onRefreshState() {
  PromiseAPIWrapper api = new PromiseAPIWrapper(mAdm, mApi);
  mAdm.when(api.getTargetState()
  ).then(new DoneCallback<LEDState>() {
    @Override
    public void onDone(LEDState state) {
      if (getActivity() == null) {
        return;
      }
      if (state.power) {
        mTextViewStatePower.setText("Power: ON");
      } else {
        mTextViewStatePower.setText("Power: OFF");
      }
      mTextViewStateBrightness.setText("Brightness: " + state.brightness);
      mTextViewStateMotion.setText("Motion: " + state.motion);
      showToast("The state has been refreshed.");
    }
  }).fail(new FailCallback<Throwable>() {
    @Override
    public void onFail(final Throwable tr) {
      showToast("Failed to receive the state: " + tr.getLocalizedMessage());
    }
  });
}

ボタンがクリックされると、すぐに PromiseAPIWrapper の getTargetState() メソッドが呼び出されます。このメソッドは作業スレッドでステートを取得し、成功時は取得したステートを LEDState クラスに格納して onDone() メソッドが呼び出されます。

ステートは、初期登録 の際に指定した LEDState で取得できます。各フィールドに設定された値を画面に反映します。また、トーストで The state has been refreshed. を表示します。

PromiseAPIWrapper での getTargetState() の実装は以下のとおりです。postNewCommand と同様に、ThingIFAPI の getTargetState() を作業スレッドで呼び出す処理が記述されています。

public Promise<LEDState, Throwable, Void> getTargetState() {
  return mAdm.when(new DeferredAsyncTask<Void, Void, LEDState>() {
    @Override
    protected LEDState doInBackgroundSafe(Void... voids) throws Exception {
      return mApi.getTargetState(LEDState.class);
    }
  });
}

次は...

コマンドリザルトの受信方法について説明します。コマンドリザルトはプッシュ通知を契機に取得するため、プッシュ通知の実装を含めて解説します。

コマンドリザルトの取得 に移動してください。

より詳しく学びたい方へ