- 投稿日:2021-03-08T22:13:53+09:00
ビジュアルプログラミング(MIT App Inventor)で開発した Androidアプリから #toio の BLE制御を行う
はじめに
ビジュアルプログラミングで Androidアプリが開発できる MIT App Inventor(以下、App Inventor と記載)に関する記事で、BLE通信を使った #toio の制御を行う話です。
以前作ったもの
App Inventor に関し、最近は以下の記事に書いた「音の機械学習や音声合成を使うアプリ」を試しに作っていました。
- ビジュアルプログラミングの MIT App Inventor を用いた音の機械学習を利用する Androidアプリ開発【後編:アプリ実装】 - Qiita
- ビジュアルプログラミングで Androidアプリ開発ができる「MIT App Inventor」を試す(ボタンを押したら音声でしゃべるアプリを作る) - Qiita
App Inventor で BLEを使う
App Inventor で BLE を使うには、以下の拡張機能のページに掲載された「BluetoothLE(BluetoothLE.aix)」を読み込んで使う必要があります。
●MIT App Inventor Extensions
https://mit-cml.github.io/extensions/
なお、冒頭に掲載していた 2つの記事のうち、音の機械学習を行う内容だったほうは、ここに掲載されている「PersonalAudioClassifier」を読み込んで作っています。
アプリを作る
今回は前回書いた記事と同様、MIT公式のバージョンではなく日本語化プロジェクトの日本語版を使って作っています。
アプリを作る細かな手順は今回は省略してますので、それに関する補足などは冒頭で掲載していた以下の記事をご参照ください
●ビジュアルプログラミングで Androidアプリ開発ができる「MIT App Inventor」を試す(ボタンを押したら音声でしゃべるアプリを作る) - Qiita
https://qiita.com/youtoy/items/93f7c786ff9d664d3032それでは、、手順の大まかな内容のみ書いていきます。
画面のデザインを編集する
プロジェクトを新規作成し、拡張機能の「BluetoothLE.aix」を読み込んでください。
拡張機能の読み込みは、左側のメニューの一番下にある「エクステンション」の中の「Import extension」から行います。
拡張機能を読み込んだら、以下のようにコンポーネントを配置します。
ここで、上記の画面を作るために行った内容を、少し補足します。
画面上に配置したものは、画面の上から置いた順に書いていくと以下のとおりです。「ボタン」の 4つ・3つのまとまりのものは、「横並び」の中に入るように配置します。
- 「レイアウト の 横並び」
- 「ユーザーインターフェース の ボタン」 × 4つ
- 「レイアウト > 横並び」
- 「ユーザーインターフェース の ボタン」 × 3つ
- 「ユーザーインターフェース の ラベル」
- 「ユーザーインターフェース の リストビュー」
- 「エクステンション の BluetoothLE」 ※ 画面上には表示されません
- 「センサー の 加速度センサー」 ※ 画面上には表示されません
そして、上記のボタンやラベルの名前・表示するテキストなどを、以下の対応関係になるように設定しています。
- 「横並び」: (変更なし)
- 「ボタン」: スキャン
- 「ボタン」: スキャン停止
- 「ボタン」: 接続
- 「ボタン」: 切断
- 「横並び」: (変更なし)
- 「ボタン」: 音を鳴らす
- 「ボタン」: LED点灯
- 「ボタン」: LED消灯
- 「ラベル」: ステータス
- 「リストビュー」: BLEリスト
- 「BluetoothLE」: (変更なし)
- 「加速度センサー」: (変更なし)
なお上記の画面作成について、2つ目の「横並び」以外の部分は、以下の公式チュートリアルの内容を見て作った構成です。
●App Inventor + IoT: Basic Bluetooth Connection Setup
> http://iot.appinventor.mit.edu/assets/tutorials/MIT_App_Inventor_Basic_Connection.pdfプログラムを作る
ここで、プログラムの内容を少し補足していきます。
このプログラムで 11個のブロックの固まりがあるのですが、その中の 7つは以下の公式チュートリアルを見て作ったものです。●App Inventor + IoT: Basic Bluetooth Connection Setup
> http://iot.appinventor.mit.edu/assets/tutorials/MIT_App_Inventor_Basic_Connection.pdf具体的には、以下のブロックです(※ 上の画像とは、並びを少し変えています)。
これらのブロックは、以下の動作を行わせるためのものです。
- 「スキャン」ボタンが押されたらデバイスのスキャンを行って、見つかったデバイスの情報をリストビューに表示
- 「スキャン停止」ボタンが押されたらデバイスのスキャンを止める
- リストビューに表示されたデバイスを選んだ状態で、「接続」ボタンを押したらデバイスへの接続を行う
- 「切断」ボタンが押されたら、デバイスとの接続を切る
また、上記の動作に合わせて、画面のラベルの表示を変えたり、リストビューが不可視になるかどうかを制御していたりします。
ここからは、デバイスとの接続が行われた状態で動作させるブロックについて補足します。
それに該当するのが以下のブロックです(※ 上の画像とは、並びを少し変えています)。
4つあるブロックの固まり全てで、最初にデバイスとの接続が行われているかをチェックしています。そして、接続済みであれば、以下の動作が行われるようにしています。
- 「ボタン: 音を鳴らす」が押されたら、特定の音を鳴らす
- 「ボタン: LED点灯」が押されたら、LED を特定の色で点灯させる
- 「ボタン: LED消灯」が押されたら、LED を消灯される
- スマホが揺さぶられたら、特定の音を鳴らす(加速度センサーで揺れを検知)
そして、それぞれの処理で「WriteBytes」の処理を行う部分で、2つの UUID や値などを設定しています。
2つの UUID は、以下の toio の仕様が書いてあるページのものを使います。▼ サービスの UUID が書いてある部分(4つのブロックの固まり共通で使っているもの)
●通信概要 · toio™コア キューブ 技術仕様
https://toio.github.io/toio-spec/docs/ble_communication_overview
▼ 音を鳴らす処理の Characteristic UUID が書いてある部分
●サウンド · toio™コア キューブ 技術仕様
https://toio.github.io/toio-spec/docs/ble_sound
▼ ランプを点灯・消灯させる処理の Characteristic UUID が書いてある部分
●ランプ · toio™コア キューブ 技術仕様
hhttps://toio.github.io/toio-spec/docs/ble_light
そして、特定の音を鳴らしたり、特定の色でランプを点灯させたり、その指示を出すための値の指定も、同様に上記の仕様に書かれたものを使っています。
例えば、「ボタン: 音を鳴らす」が押された時の処理は、以下を見て設定しています。
ブロックの中でいうと、以下の赤枠で囲んだ部分です。
音量について、仕様で最大音量0xFF
というのが 16進数で書かれていますが、それを上記のブロックで指定する場合、置くべきブロックは数値となるようでした。そこで、10進数にした値の255
を使っています。
さらに、複数の値を指定するには、リストを使って複数の数値を設定すれば良いようでした。動作している様子
上記の手順を進めて作ったアプリを、実際に動かしてみると以下のようになります。
動画で出ている部分の前にスキャンと toio への接続をすませており、この動画では音を鳴らしたりランプを制御したりする部分をご覧いただけるようにしています。ビジュアルプログラミング(MIT App Inventor)による Androidアプリでの BLE利用。#toio への接続後、ボタンを押して音を鳴らしたり、ボタン押下でのランプの点灯/消灯をやって、最後にスマホを振ったら音が鳴る、という動作をさせた様子の動画。 pic.twitter.com/3mO2xAVB9o
— you (@youtoy) March 7, 2021終わりに
- 投稿日:2021-03-08T22:13:53+09:00
ビジュアルプログラミング(MIT App Inventor)で開発した Androidアプリから #toio の制御を行う(BLE用の拡張機能を利用)
はじめに
ビジュアルプログラミングで Androidアプリが開発できる MIT App Inventor(以下、App Inventor と記載)に関する記事で、BLE通信を使った #toio の制御を行う話です。
以前作ったもの
App Inventor に関し、最近は以下の記事に書いた「音の機械学習や音声合成を使うアプリ」を試しに作っていました。
- ビジュアルプログラミングの MIT App Inventor を用いた音の機械学習を利用する Androidアプリ開発【後編:アプリ実装】 - Qiita
- ビジュアルプログラミングで Androidアプリ開発ができる「MIT App Inventor」を試す(ボタンを押したら音声でしゃべるアプリを作る) - Qiita
App Inventor で BLEを使う
App Inventor で BLE を使うには、以下の拡張機能のページに掲載された「BluetoothLE(BluetoothLE.aix)」を読み込んで使う必要があります。
●MIT App Inventor Extensions
https://mit-cml.github.io/extensions/
なお、冒頭に掲載していた 2つの記事のうち、音の機械学習を行う内容だったほうは、ここに掲載されている「PersonalAudioClassifier」を読み込んで作っています。
アプリを作る
今回は前回書いた記事と同様、MIT公式のバージョンではなく日本語化プロジェクトの日本語版を使って作っています。
アプリを作る細かな手順は今回は省略してますので、それに関する補足などは冒頭で掲載していた以下の記事をご参照ください
●ビジュアルプログラミングで Androidアプリ開発ができる「MIT App Inventor」を試す(ボタンを押したら音声でしゃべるアプリを作る) - Qiita
https://qiita.com/youtoy/items/93f7c786ff9d664d3032それでは、、手順の大まかな内容のみ書いていきます。
画面のデザインを編集する
プロジェクトを新規作成し、拡張機能の「BluetoothLE.aix」を読み込んでください。
拡張機能の読み込みは、左側のメニューの一番下にある「エクステンション」の中の「Import extension」から行います。
拡張機能を読み込んだら、以下のようにコンポーネントを配置します。
ここで、上記の画面を作るために行った内容を、少し補足します。
画面上に配置したものは、画面の上から置いた順に書いていくと以下のとおりです。「ボタン」の 4つ・3つのまとまりのものは、「横並び」の中に入るように配置します。
- 「レイアウト の 横並び」
- 「ユーザーインターフェース の ボタン」 × 4つ
- 「レイアウト > 横並び」
- 「ユーザーインターフェース の ボタン」 × 3つ
- 「ユーザーインターフェース の ラベル」
- 「ユーザーインターフェース の リストビュー」
- 「エクステンション の BluetoothLE」 ※ 画面上には表示されません
- 「センサー の 加速度センサー」 ※ 画面上には表示されません
そして、上記のボタンやラベルの名前・表示するテキストなどを、以下の対応関係になるように設定しています。
- 「横並び」: (変更なし)
- 「ボタン」: スキャン
- 「ボタン」: スキャン停止
- 「ボタン」: 接続
- 「ボタン」: 切断
- 「横並び」: (変更なし)
- 「ボタン」: 音を鳴らす
- 「ボタン」: LED点灯
- 「ボタン」: LED消灯
- 「ラベル」: ステータス
- 「リストビュー」: BLEリスト
- 「BluetoothLE」: (変更なし)
- 「加速度センサー」: (変更なし)
なお上記の画面作成について、2つ目の「横並び」以外の部分は、以下の公式チュートリアルの内容を見て作った構成です。
●App Inventor + IoT: Basic Bluetooth Connection Setup
> http://iot.appinventor.mit.edu/assets/tutorials/MIT_App_Inventor_Basic_Connection.pdfプログラムを作る
ここで、プログラムの内容を少し補足していきます。
このプログラムで 11個のブロックの固まりがあるのですが、その中の 7つは以下の公式チュートリアルを見て作ったものです。●App Inventor + IoT: Basic Bluetooth Connection Setup
> http://iot.appinventor.mit.edu/assets/tutorials/MIT_App_Inventor_Basic_Connection.pdf具体的には、以下のブロックです(※ 上の画像とは、並びを少し変えています)。
これらのブロックは、以下の動作を行わせるためのものです。
- 「スキャン」ボタンが押されたらデバイスのスキャンを行って、見つかったデバイスの情報をリストビューに表示
- 「スキャン停止」ボタンが押されたらデバイスのスキャンを止める
- リストビューに表示されたデバイスを選んだ状態で、「接続」ボタンを押したらデバイスへの接続を行う
- 「切断」ボタンが押されたら、デバイスとの接続を切る
また、上記の動作に合わせて、画面のラベルの表示を変えたり、リストビューが不可視になるかどうかを制御していたりします。
ここからは、デバイスとの接続が行われた状態で動作させるブロックについて補足します。
それに該当するのが以下のブロックです(※ 上の画像とは、並びを少し変えています)。
4つあるブロックの固まり全てで、最初にデバイスとの接続が行われているかをチェックしています。そして、接続済みであれば、以下の動作が行われるようにしています。
- 「ボタン: 音を鳴らす」が押されたら、特定の音を鳴らす
- 「ボタン: LED点灯」が押されたら、LED を特定の色で点灯させる
- 「ボタン: LED消灯」が押されたら、LED を消灯される
- スマホが揺さぶられたら、特定の音を鳴らす(加速度センサーで揺れを検知)
そして、それぞれの処理で「WriteBytes」の処理を行う部分で、2つの UUID や値などを設定しています。
2つの UUID は、以下の toio の仕様が書いてあるページのものを使います。▼ サービスの UUID が書いてある部分(4つのブロックの固まり共通で使っているもの)
●通信概要 · toio™コア キューブ 技術仕様
https://toio.github.io/toio-spec/docs/ble_communication_overview
▼ 音を鳴らす処理の Characteristic UUID が書いてある部分
●サウンド · toio™コア キューブ 技術仕様
https://toio.github.io/toio-spec/docs/ble_sound
▼ ランプを点灯・消灯させる処理の Characteristic UUID が書いてある部分
●ランプ · toio™コア キューブ 技術仕様
hhttps://toio.github.io/toio-spec/docs/ble_light
そして、特定の音を鳴らしたり、特定の色でランプを点灯させたり、その指示を出すための値の指定も、同様に上記の仕様に書かれたものを使っています。
例えば、「ボタン: 音を鳴らす」が押された時の処理は、以下を見て設定しています。
ブロックの中でいうと、以下の赤枠で囲んだ部分です。
音量について、仕様で最大音量0xFF
というのが 16進数で書かれていますが、それを上記のブロックで指定する場合、置くべきブロックは数値となるようでした。そこで、10進数にした値の255
を使っています。
さらに、複数の値を指定するには、リストを使って複数の数値を設定すれば良いようでした。動作している様子
上記の手順を進めて作ったアプリを、実際に動かしてみると以下のようになります。
動画で出ている部分の前にスキャンと toio への接続をすませており、この動画では音を鳴らしたりランプを制御したりする部分をご覧いただけるようにしています。ビジュアルプログラミング(MIT App Inventor)による Androidアプリでの BLE利用。#toio への接続後、ボタンを押して音を鳴らしたり、ボタン押下でのランプの点灯/消灯をやって、最後にスマホを振ったら音が鳴る、という動作をさせた様子の動画。 pic.twitter.com/3mO2xAVB9o
— you (@youtoy) March 7, 2021終わりに
今回、App Inventor とその拡張機能を使い、BLE通信を使った #toio との接続・制御を行いました。
そして、掲載していた動画の内容のとおり、無事に動作させることができました。今後は、toio から値を受け取る処理の実装も試すことができたらと思います。
気になる点
今回は使ってない部分で気になるところがあり、具体的には toio で値をやりとりする仕様の中で 2バイトを使って 255より大きい値を扱うところ(例えば、専用マットの位置座標を扱うところ)です。
今回のような数値を指定する形で、エンディアンを考慮した意図通りのバイトオーダーになるか・それを簡単に扱えるか、という点なのですが、そのあたりは今後確かめていこうと思っています。
- 投稿日:2021-03-08T19:29:34+09:00
Azure PipelinesのYAMLでAndroidアプリのApp Center配布パイプラインを構築する方法
「Azure PipelinesのYAMLでAndroidアプリのCI/CD環境を構築する」は3部構成です。
記事を順番に読み進めると、Azure PipelinesでAndroidアプリのCI/CD環境が構築できるようになります。
- 第一部:CI環境の構築
- 第二部:App Center配布パイプラインの構築 ←イマココ
- 第三部:Google Play Console配布パイプラインの構築(未投稿)
はじめに
Azure Pipelinesを使い、AndroidアプリをApp Centerへ配布するCDを構築します。
本記事で説明しないこと
- Azure Pipelinesの概要や基本的な操作方法
私が以前書いた記事が参考になると思います- Visual Studio App Centerの概要や基本的な操作方法
- CI環境の構築で説明した内容
以前説明した内容を説明するのは冗長なのでしませんApp Centerのコネクションを追加
Azure PipelinesのYAMLでiOSアプリのApp Center配布パイプラインを構築する方法 と同様なので省略します。
キーストアのアップロード
必要に応じてキーストアをSecure fileへアップロードします。
アップロードの方法は こちら をご参照ください。私はApp Center用のキーストアはリポジトリに直接コミットしており、Secure fileは使っていません。
キーストアと鍵のパスワードの追加
必要に応じてキーストアと鍵のパスワードをVariablesに追加します。
追加方法は こちら をご参照ください。私はApp Center用のキーストアと鍵のパスワードは
/app/build.gradle
に直接書いています。設定ファイルの作成
今回はビルドタイプを
debug
に固定し、プロダクトフレーバーを以下の3つすべてでApp Centerに配布できるようにします。
develop
staging
production
プロダクトフレーバーが異なる以外は同じ処理なので、Azure DevOpsのテンプレートを利用し、共通処理を別のYAMLファイルに抜き出します。
まずは全プロダクトフレーバーの設定ファイルを作成します。
見てわかる通りproductFlavor
に渡す値のみ変えています。distribute-appcenter-develop-debug.ymltrigger: none jobs: - job: distribute_appcenter_develop_debug pool: vmImage: 'ubuntu-latest' steps: # App Centerへ配布 - template: templates/distribute-appcenter-debug-template.yml parameters: productFlavor: 'develop'distribute-appcenter-staging-debug.ymltrigger: none jobs: - job: distribute_appcenter_staging_debug pool: vmImage: 'ubuntu-latest' steps: # App Centerへ配布 - template: templates/distribute-appcenter-debug-template.yml parameters: productFlavor: 'staging'distribute-appcenter-production-debug.ymltrigger: none jobs: - job: distribute_appcenter_production_debug pool: vmImage: 'ubuntu-latest' steps: # App Centerへ配布 - template: templates/distribute-appcenter-debug-template.yml parameters: productFlavor: 'production'次にテンプレートを作成します。
templates/distribute-appcenter-debug-template.ymlparameters: - name: productFlavor type: string steps: # JDKのセットアップ - task: JavaToolInstaller@0 inputs: versionSpec: '8' jdkArchitectureOption: 'x64' jdkSourceOption: 'PreInstalled' # 依存関係の出力 - script: ./gradlew androidDependencies displayName: Displays the Android dependencies of the project # APKの生成 - script: ./gradlew assembleDebug displayName: Generate APK for debug # アーティファクトのステージングへコピー - task: CopyFiles@2 inputs: Contents: | **/app/build/outputs/apk/${{ parameters.productFlavor }}/debug/app-${{ parameters.productFlavor }}-debug.apk TargetFolder: '$(Build.ArtifactStagingDirectory)' # アーティファクトへアップロード - task: PublishBuildArtifacts@1 inputs: pathtoPublish: '$(Build.ArtifactStagingDirectory)' artifactName: 'drop' publishLocation: 'Container' # App Centerへ配布 - task: AppCenterDistribute@3 inputs: serverEndpoint: 'App Center' appSlug: '{Organization}/{App}' appFile: '**/app/build/outputs/apk/${{ parameters.productFlavor }}/debug/app-${{ parameters.productFlavor }}-debug.apk' releaseNotesOption: 'input' releaseNotesInput: | - Product Flavor:${{ parameters.productFlavor }} - Build Type:debug - Keystore:{Keystore name} - Branch:$(Build.SourceBranchName) - Last Commit ID:$(Build.SourceVersion) - Last Commit Comment:$(Build.SourceVersionMessage) - Release Note:$(ReleaseNote) destinationType: 'groups'App CenterはAAB形式に対応していないため、APK形式でアップロードします。
参考: https://github.com/microsoft/appcenter/issues/955AAB形式でアップロードしようとすると、以下のエラーが出力されます。
##[error]{"code":"not_supported","message":"Error: Distribution of .aab is not supported for groups/testers"}他は基本的に Azure PipelinesのYAMLでiOSアプリのApp Center配布パイプラインを構築する方法 と同様なので省略します。
おわりに
Azure PipelinesのYAMLでAndroidアプリをApp Centerへ配布することができました!
テンプレートを利用することで共通処理をまとめられ、設定ファイルがスッキリしました。
参考リンク
APK
Templates - Azure Pipelines
- Templates - Azure Pipelines | Microsoft Docs
- (114) Azure Multistage Pipelines Part3 - YouTube
- https://twitter.com/kkamegawa/status/1362985070114447364
App Center
- 投稿日:2021-03-08T18:20:41+09:00
JAVA Convert short[] to byte[]
Method 1:
byte [] ShortToByte_ByteBuffer_Method(short [] input) { int index; int iterations = input.length; ByteBuffer bb = ByteBuffer.allocate(input.length * 2); for(index = 0; index != iterations; ++index) { bb.putShort(input[index]); } return bb.array(); }Method 2:
byte [] ShortToByte_Twiddle_Method(short [] input) { int short_index, byte_index; int iterations = input.length; byte [] buffer = new byte[input.length * 2]; short_index = byte_index = 0; for(/*NOP*/; short_index != iterations; /*NOP*/) { buffer[byte_index] = (byte) (input[short_index] & 0x00FF); buffer[byte_index + 1] = (byte) ((input[short_index] & 0xFF00) >> 8); ++short_index; byte_index += 2; } return buffer; }
- 投稿日:2021-03-08T14:39:51+09:00
Navigation Componentで新規登録画面の実装方法(graphのネストと戻るボタンの実装)
はじめに
Navigation Component を使うと新規登録画面の画面遷移が簡単に実装できると耳にしました。
公式サイトにも実装方法が記載されていますが、なかなか難しかったので記事としてまとめます。動作環境
この記事の動作環境は以下のとおりです。
Android Studio:4.1.1
Kotln:1.4.21
Open JDK:1.8
compileSdkVersion:30
targetSdkVersion:30
minSdkVersion:23
Navigation Component:2.3.2目標
以下を目標とします。
- Navigation Component UIで新規登録の画面遷移を実装できる
動作イメージ
こんな動きをする新規登録の画面遷移を Navigation Component で実装したい!!
機能概要
よくある話ですが、アプリをインストールして 新規登録 をタップして、ウィザード形式でユーザ登録などを行います。
登録が完了した画面や登録完了後に戻ってきたログイン画面で戻るボタンなどをタップすると正しい画面遷移ができています。
下図のようなイメージです。これってどのように実装しているのだろうと不思議に思うこともあります。
Navigation Componentに、公式サイトに実現の助けになるような機能が搭載されています。
この記事では実現方法を説明していきます。Fragmentの動作
まず、実装方法の前にFragmentの画面やオブジェクトがどのように管理されているか理解して置く必要があります。
Navigation Componentでは、Fragmentの画面はActivityと同じ用にスタックで管理されています。
下図様なイメージです。そのため、完了画面に遷移したあと、戻るボタンをタップするとデフォルトの動きでは確認画面に遷移していまいます。
これがFragmentの基本的な動作となります。
そのため、完了画面から戻るボタンや戻る機能を追加するときに、Login画面までスタックをクリアする必要があります。
上記の内容を理解した上で、実装方法を確認してください。実装方法
前提知識
実装方法の前提知識としては、この記事を理解しておいてください。
アクション
画面遷移でスタックをクリアしたい画面にアクションを接続することにより実現可能です。
下図の様なイメージで、完了画面からログイン画面にアクションを接続します。graphのネスト
デスティネーションが増えていくと、navigationファイルの編集画面が操作しづらくなってしまいます。
なので、機能毎などでgraphをネストするとわかりやすくなります。1機能のデスティネーションをすべて選択した状態で、「 group into nest graph 」ボタンをクリックします。
操作方法は下図を参照してください。「 group into nest graph 」ボタンをクリックすると、ネストしたgraphは 角がまるい四角 になります。
ネストしたgraphの詳細を確認したい場合は、 角がまるい四角 をダブルクリックするだけで下図が表示されます。ネストしたgraphからもとの画面に戻りたい時は、Component Treeで外側をクリックすると元の画面に戻ります。
実際のコードを確認すると、navigationタグがネストしていることが確認できます。
ネストを利用することにして、機能ごとにnavigaitonをまとめられるので便利ですね。
navigationファイルを新規作成してincludeしても同じ事が行なえます。スタックを指定したFragmentまでクリアする
先に説明した通り、ウィザード形式のように元の画面までスタックをクリアするには以下の手順を行います。
- アクションに設定を追加する
アクションタグの属性に以下の2つを設定します。
- popUpTo属性
- popUpToInclusive属性
最終的に下記のようなアクションになります。
<action android:id="@+id/action_completeToRegisterUserFragment_to_loginFragment" app:destination="@id/loginFragment" app:popUpTo="@id/loginFragment" app:popUpToInclusive="true" />popUpTo属性
公式サイトに説明があります。
Navigation ライブラリに対し、navigate() 呼び出しの一環として、バックスタックからいくつかのデスティネーションをポップするように指示します。属性値として、スタック上に残す最も新しいデスティネーションの ID を指定します。
スタックにある、navigationは一番新しいデスティネーションを探し出してくれるみたいですね。
しかし、これだけではうまく動作しません。popUpToInclusive属性
こちらも公式サイトに説明があります。
app:popUpToInclusive="true" を追加すると、app:popUpTo 内で指定したデスティネーションもバックスタックから削除するように指示できます。
これで古いLogin画面を削除してアクションので指定しているデスティネーションを新規にスタックに乗っけているわけですね。
なるほど、その他の説明もかいてありますが、興味のある方は公式サイトを参照してください。
戻るボタンの処理を変更する
Androidで用意されているソフトウェアやハードウェアの戻るボタンの挙動も修正しなければなりません。
公式サイトに詳しく書かれていますが、どうやら ** OnBackPressedDispatcher#addCallback** で戻るボタンの挙動を変えるみたいです。実際のコードは以下の通りです。
// 戻るボタンを押下されても、ログイン画面に戻るようにこの画面のライフサイクル中の戻るボタンのコールバックを変更 requireActivity().onBackPressedDispatcher.addCallback(this) { val navController = findNavController() val action = CompleteToRegisterUserFragmentDirections.actionCompleteToRegisterUserFragmentToLoginFragment() navController.navigate(action) }addCallback() メソッドの引数に ライフサイクルオーナーを渡す方法 と 渡さない方法 があります。
違いは以下のとおりです。
方法 挙動 ライフサイクルオーナーを渡す方法 そのライフサイクルの間、Callbackで指定した戻るボタンの挙動が有効になる ライフサイクルオーナーを渡さない方法 アプリが終了するまで、Callbackで指定した戻るボタンの挙動が有効にになる 今回のケースでは、ライフサイクルオーナーを渡す方法が正しいとなります。
以上で実装は完了です。
まとめ
Androidアプリでウィザード形式を実装する方法がとても簡単になりました。
Navigation Componentを今まで避けて通ってきてきた私でしたが、今後は積極的に利用したくなりました。
- 投稿日:2021-03-08T11:13:33+09:00
Android API29未満で getRawX(index)をする(回転、拡大、縮小に対応)
getX()とgetRawX()
MotionEventにはgetX()とgetRawX()という異なるメソッドがあります。
(もちろん同様にy座標に関するメソッドもあります)この2つのメソッドの違いは、getX()はEventの対象となるViewのローカル座標、getRawX()はスクリーン上の座標を取得するという点になります。
getRawX()とgetRawX(index)
API29からgetRaw(index)というメソッドが追加されました。
MotionEventではタッチされている座標(pointer)が複数ある場合があり、indexを指定することでpointerごとの座標を取得することができます。しかし、getRawX(index)はAPI29から追加されたメソッドのため、API29未満では自分で計算を行うことになります。
API29未満にもgetX(index)というメソッドがあります、これは指定したindexのpointerのローカル座標を取得するメソッドです。このメソッドを利用して計算をします。ローカル座標からスクリーン座標への変換
具体的なコードは以下になります。
Viewが回転、拡大、縮小していた場合にも正しい座標が取得できるようになっています。
回転、拡大、縮小が不要な場合には該当のコードを削除してください。private fun getRawPoint(view: View, event: MotionEvent, index: Int): PointF { val location = intArrayOf(0, 0) view.getLocationOnScreen(location) var x = event.getX(index) * view.scaleX var y = event.getY(index) * view.scaleY var angle = Math.toDegrees(atan2(y.toDouble(), x.toDouble())) angle += view.rotation.toDouble() val length = hypot(x, y) x = (length * cos(Math.toRadians(angle))).toFloat() + location[0] y = (length * sin(Math.toRadians(angle))).toFloat() + location[1] return PointF(x, y) }scaleが変更されていた場合を考慮し、x, yの値にscaleをかけています。
また、回転していた場合を考慮し、アークタンジェントを求めるatan2(y, x)を利用して座標から角度を求めrotationと合計しています。
解説のため下図を用意しました。
rotationでαの角度、atan2(y, x)でβの角度を求めています。
lengthが三角関数の斜辺となりα + βが三角関数のθとなるのであとはsin、cosで座標が求められますね。API29未満でMotionEventからスクリーン座標を取得したいときにお使いください。
- 投稿日:2021-03-08T07:48:44+09:00
【Flutter】Flutter2.0で何が変わるのか?
Flutter2.0のリリース発表
2021年3月3日水曜日にFlutter2.0が発表されました。
5つのOSへの対応、WEBブラウザへの正式対応
待望のFlutterのメジャーアップグレード
今回のアップグレードにより、Web、モバイル、デスクトップアパリケーションを正式にサポートいたしました。Flutter2.0では、基本の部分において、同じソースコードを使用して、ネイティブアプリ(iOS、Android)、Windows、macOS、Linuxの5つのOSにリリースできます。
※また、Chrome、Firefox、Safari、Edgeなどのブラウザを対象としたWebも含まれます。Flutterは、車、テレビ、スマートホーム関連のモジュールに組み込むこともできます。
Playストアだけでもすでに150,000を超えるFlutterアプリがあり、Alibaba、Tencent、Baidu、WeChat、Grab、Yandex Go、Nubank、Sonos、Fastic、Betterment、realtor.com などの人気アプリを含む世界中の顧客がFlutterを使用しています。
Flutterの効率化
Googleの1,000人を超えるエンジニアがDartとFlutterを使用してアプリを構築しています。
Stadia、Google One、Google Nest Hubなど、これらの製品のFlutterで構築されています。
Google Payは、数か月前に主力のモバイルアプリとしてFlutterに切り替えましたが、すでに生産性と品質が大幅に向上しています。チームはソースコードを統合することで、プラットフォーム間の機能の違いを取り除き、50万行を超えるコードを排除しました。Google Payは、はるかに効率的であり、技術的負債が大幅に削減され、iOSとAndroidの両方でセキュリティレビューや実験などの統合リリースプロセスが行われると報告しています。
GooglePayがFlutter採用してこの辺りの実例は覚えておくと役立ちそう。
— coka @Flutterライフ (@coka__01) March 6, 2021
・170万行→110万行に
・技術的負債が90%減
・エンジニアの生産性が20%向上Flutter WEB
今回の初期リリースは、特に3つのアプリケーションにフォーカスしています。
- PWA
- SPA
- 既存のFlutterモバイルアプリのWebへの拡張
TOYOTAのFlutter採用
世界で最も売れている自動車メーカーであるトヨタは、Flutterを搭載したシステムを構築することにより、市場で最高のデジタル体験を車両にもたらす計画を発表しました。
? The future of @Toyota's infotainment systems will be powered by Flutter.@ToyotaConnected is building Flutter right into the heart of their vehicles. Catch @danielthall at #FlutterEngage as he talks more about their plans with us!
— Flutter (@FlutterDev) March 3, 2021
On now ? https://t.co/T9025C5NCV pic.twitter.com/pSn299QF9P個人的に便利になりそうなこと
コマンドラインからのIPAファイルの生成
flutter build ipa
のコマンドにより、Xcodeを開かずに、IPAファイルを生成することが可能になりました。
https://github.com/flutter/flutter/pull/67781テキストの自動補完ライブラリの追加
AutocompleteCoreというライブラリの追加により、テキストボックス等への入力時に候補を表示したりする機能が提供されました。
Flutter Fix
Flutterのメンテナンス速度は驚くほど速く、かなりの更新が発生します。
そのため、非推奨となってしまうコードも多いです。ですがそのような問題に対しても、以下のコマンドで自動的に非推奨の箇所を明示してくれるようです。
$ dart fix --dry-runまた、自動で修正をさせたい場合は以下のコマンドで実行できます。
$ dart fix --applyDevTools 「Enable Invert Oversized Images」
表示されているよりも高い解像度の画像を簡単に確認できる機能です。これにより、アプリの過剰なサイズとメモリ使用量を追跡できます。この機能を有効にすると、フラッターインスペクターで特大画像が反転して表示されます。
DartのNullSafetyサポート
Flutter2と同時にDartの2.12が発表され、待望のNull Safetyがリリースされました。
参考記事
- 投稿日:2021-03-08T00:17:21+09:00
(要注意)CoroutineのasyncはConcurrencyが必ずParallelismではないこと
COROUTINEの並列実行の速度測定する為、
本来FLUX(reactor-core)の部分をCOROUTINEに変える時の発見なんです。タスクはあるウェブサイトから画像264枚をダウンロードし、JPGファイルとして保存する。
私のノートパソコンはWINDOWS 10、AMD Ryzen 5 3500Uだから
以下の処理は8 Threadの並列実行になります。FLUX(reactor-core)
Flux.fromIterable(taskStream.map { Mono.fromCallable { it.invoke() }.onErrorResume { Mono.empty() } }) .parallel() .runOn(Schedulers.parallel()) .flatMap { x: Mono<Boolean> -> x } .subscribe(onProcess, whenError, whenFinish)結果
...
/galleries/1809504/262.jpg
/galleries/1809504/263.jpg
/galleries/1809504/264.jpg
Calculation of Flux time :53075 millisecondsCoroutine Async
Kotlin Coroutine 入門2: 並列実行と Structured Concurrency と例外 を参考して以下を作成。
taskStream.map { activeScope.async { it.invoke() } }.awaitAll()結果
...
/galleries/1809504/262.jpg
/galleries/1809504/263.jpg
/galleries/1809504/264.jpg
Calculation of Coroutine time :340325 milliseconds原因
え。。Fluxより6.41倍の時間も掛かった。これは間違いなく1 Threadの実行結果。
でも上の記事ではasyncを使って2秒のタスク二つを2秒で完成したはず。これは何のことでしょう!?答えはここに見つけた:
CONCURRENT COROUTINES – CONCURRENCY IS NOT PARALLELISM
簡単に言うとKotlin Coroutine 入門2の例は実際はdelay(2000)を使って何にもしてないからだ。
Coroutineでは1ThreadでもdelayとかawaitとかSuspend関係のコードがあったら、
その暇を利用して他のタスクを実行する!だからdelay(2000)の二つは2.165秒で完成出来た。
しかし、実際CPUの計算を2秒掛かったタスクの場合は4秒以上になってしまう。
入門2の例は並行処理だ、並列処理ではない。並列処理
CONCURRENCY IS NOT PARALLELISMからは実際の並列実行(Parallel Coroutines)を必要の条件も書いてる
1 Run in GlobalScope (GlobalScopeを使う)
val one = GlobalScope.async { doSomethingUsefulOne() } val two = GlobalScope.async { doSomethingUsefulTwo() }2 Specify a coroutine dispatcher (dispatcherを指定する)
val one = async(Dispatchers.Default) { doSomethingUsefulOne() } val two = async(Dispatchers.Default) { doSomethingUsefulTwo() }改正
早速改正して
taskStream.map { activeScope.async(Dispatchers.Default) { it.invoke() } }.awaitAll()結果
...
/galleries/1809504/262.jpg
/galleries/1809504/263.jpg
/galleries/1809504/264.jpg
Calculation of Coroutine time :56176 millisecondsこれはFluxと完全一致の並列実行速度。そしてこの簡潔な表現、Kotlinやっぱり素晴らしい!