- 投稿日:2020-09-24T18:49:49+09:00
11. 【Android/Kotlin】Toast
はじめに
DreamHanksのMOONです。
前回はライブラリを追加する方法について説明しました。
10. 【Android/Kotlin】ライブラリを追加今回は
Toast
という通知メッセージについて説明していきます。Toastとは
Toastはみんなさんが考えている
トーストパン
の意味と同じです。
トースト機器でトーストが完成すると飛び出るようなものだという意味で、
通知メッセージが画面に現れることを意味します。今回はこのテキストを入力し、Toastメッセージにテキストを表示していきます。
Toast追加
・Activityを作成
ToastActivity.ktpackage com.example.practiceapplication import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import android.widget.* class ToastActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_toast) val text_et = findViewById<EditText>(R.id.text_et) //EditText(入力エリア) val toast_btn = findViewById<Button>(R.id.toast_btn) //追加ンボタン //ボタンのクリックイベントを設定 toast_btn.setOnClickListener { //入力したテキストに対するToastメッセージを生成 Toast.makeText(applicationContext, text_et.text.toString(), Toast.LENGTH_SHORT).show() } } }ボタンクリックイベント内にToastを生成するためのコードを追加します。
activiy_toast.xml<?xml version="1.0" encoding="utf-8"?> <LinearLayout 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" android:orientation="vertical" tools:context=".ToastActivity" android:gravity="center"> <EditText android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/text_et" android:inputType="text" android:hint="テキストを入力してください。"/> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/toast_btn" android:text="ボタン"/> </LinearLayout>アプリ起動
・
こんにちは
というテキストを入力し、ボタンをクリックした場合
・
DreamHanks
というテキストを入力し、ボタンをクリックした場合
終わりに
今回は
Toast
という通知メッセージについて説明しました。次回はCircleImageViewという外部ライブラリを使用してみます。
12. 【Android/Kotlin】丸いイメージ(CircleImageView)
- 投稿日:2020-09-24T17:17:52+09:00
Android: YouTube Android Player API
- Android Studio 4.0.1
- Kotlin 1.4.0
- YouTube Android Player API 1.2.2
YouTube Android Player APIを使って、AndroidアプリでYoutubeを再生させます。
Android Studioでプロジェクト作成
アプリの登録
Google APIsでAPIキーを作成し、Androidのプロジェクトと関連付けます。
Android Studioでプロジェクト作成
プロジェクトを作成し、パッケージ名を決めます。
アプリのフィンガープリント取得
SHA-1のフィンガープリント取得方法
- AndroidStudioで、Gradleタブの「app/Tasks/android/signingReport」をダブルクリック
- Runコンソールに出力される
Googleプロジェクト作成
https://console.developers.google.com/cloud-resource-manager
既存のプロジェクトを利用してもいいかもしれませんが、作成します。
リソースの管理から、プロジェクト作成APIキー作成
https://console.developers.google.com/apis/credentials
作成したプロジェクトで
「+認証情報を作成」 → 「APIキー」 → 「閉じる」アプリと関連付け
作成されたAPIキーを選択
APIキーの名前をAPIキー1から、適当に変更Android アプリに使用を限定、のメニューから
「項目を追加」パッケージ名とSHA-1のフィンガープリントを設定ライブラリのダウンロードとセットアップ
ライブラリのダウンロード
https://developers.google.com/youtube/android/player/downloads
Androidプロジェクトに登録
ダウンロードしたzipファイルからjarファイルをコピー
libs/YouTubeAndroidPlayerApi.jar
→ [Project Folder]/app/libsAndroidStudioで、Porject/app/libs/YouTubeAndroidPlayerApi.jarを
右クリック「 Add As Library...」→ appを選択アプリ実装
パーミッション設定
AndroidManifest.xml<uses-permission android:name="android.permission.INTERNET" />回転制御
AndroidManifest.xml<activity android:name=".MainActivity" android:configChanges="orientation|screenSize|keyboardHidden">レイアウトXML編集
- Designに切り替え、Containers/をレイアウトにドロップすると、Viewクラスの選択ダイアログが表示される
- YouTubePlayerView(com.google.android.youtube.player)を選択
- ViewにIDを付ける(今回はyoutubeView)
※YoutubePlayerViewにボタンなどが重なっていると、再生が途中で止まってしまいました。
Activity実装
YouTubeBaseActivityを継承
MainActivityclass MainActivity : YouTubeBaseActivity() { val API_KEY = "[API_KEY]" override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val playerView = findViewById<YouTubePlayerView>(R.id.youtubeView) val listener = object: YouTubePlayer.OnInitializedListener { override fun onInitializationSuccess(provider: YouTubePlayer.Provider?, player: YouTubePlayer?, wasRestored: Boolean) { player?.loadVideo("[YoutubeのVideoID]") } override fun onInitializationFailure(provider: YouTubePlayer.Provider?, result: YouTubeInitializationResult?) { } } playerView.initialize(API_KEY, listener) } }
- 投稿日:2020-09-24T13:33:19+09:00
Dagger Hiltを踏まえたテストのプラクティス
Dagger HiltというGoogleがAndroid開発において推奨するDIライブラリ(JVM言語であれば使える)のこちらのドキュメントについてです。
https://dagger.dev/hilt/testing-philosophy
結構良いテストについて個人的に刺さる概念があったので、書いておきます。
またシンプルな部分以外のHiltの良いところが分かる気がします。
Dagger Hiltを踏まえたテストのプラクティスについて書かれている。
Dagger HiltのAPIや機能は何が良いテストを作るかの暗黙の哲学に基づいて作られている。ただ、良いテストというのが万人に受け入れられているわけではいので、Hiltチームにおいてのテストの哲学を明らかにするためのドキュメントとなる。何をテストするのか
Hiltは外部の"ユーザーからの観点でテストする"ことを推奨する。外部のユーザーとはたくさんの意味がある。本当のユーザーも指すし、クラスやAPIの利用者も指す。
大切なところは"実装の詳細を表現してはいけない"ということ。内部の実装に依存したテスト、例えば内部のメソッドに依存したテストを書くとテストが壊れやすくなる。internalなメソッドの名前が変わっても、良いテストは何も変更する必要がない。今のテストを壊す要因はユーザーに見える変更があったときのみになる。実際の依存関係を利用する
Hiltのテストの哲学はすべてのクラスがそれぞれテストを書くことを強制しない。実際にはそのようなルールは"ユーザーからの観点でテストする"という原則に違反する。テストは書きやすく、実行しやすくするために、必要なだけ小さくする。(高速、リソースを大量に消費しないなど)
他に違いがないのであれば、テストは以下のことを、この順番で優先する
- 依存関係の実際のコードを利用する
- ライブラリが提供する標準のFakeを利用する
- 最後の手段としてMockを利用する
しかし、これにはトレードオフがある。
- テストに置いての本物の依存関係をインスタンス化するセットアップはボイラープレートになりやすく、繰り返しになりやすい。
- バックエンドのサーバーを立ち上げる必要があるなど、パフォーマンスのトレードオフが存在する。
Hiltは最初の問題を解決する。(詳細は以下)パフォーマンスについては問題になることはあるが、ほとんどの場合では問題にならない。I/Oで依存関係がある場合のみ問題になる可能性がある。パフォーマンスを大幅に低下させることなく、実際の依存関係を利用して便利かつ堅牢に利用できる場合は、実際の依存関係を利用する必要がある。これによってテストで大きな悪い影響がある場合は、Hiltはそのバインディングを交換する方法を提供する。
より多くの実際の依存関係を使うことの大きなアドバンテージ
- 実際の依存関係は本当の問題を補足しやすい。モックのように古いまま残されたりしない。
- "ユーザーからの観点でテスト"と組み合わせることで、同じカバレッジでもっと少ないテストの量で書くことができる。
- テストが壊れることが、FakeやMockの設定ミスによる問題による問題の代わりに、実際の問題を指し示す (そして、逆に言えばテストがパスすることはコードがちゃんと動くことを意味する)
- "ユーザーからの観点でテスト"と"実際の依存関係を使う"は相性が良い。依存関係を入れ替えないため。
もし本当の依存関係が使えないのであれば、次にライブラリが提供する標準のFakeを使う。ライブラリの作者や堅牢なカバレッジで提供されることによってメンテされているのであれば、標準のFakeはMockより良い。これらの理由によりMockは最終手段となる。
HiltとDI、そしてTest
これらの基礎によって、"HiltとDI、そしてTest"に入る。"実際の依存関係を使う"についてのDagger Hiltの答えはTestでDI/Daggerを使うことである。これはもっと実際に近い、なぜならプロダクションで行われるようにオブジェクトが作られるため。これはテストがプロダクションコードより壊れにくいことを意味し、実際のオブジェクトを使いやすくする。実際、
@Inject
のコンストラクタがある場合は、Mockを作って入れるより、Daggerを使うほうが簡単で少ないコードにできる。残念なことにHiltを利用しないでこのようなテストを行うことは、ボイラープレートとDaggerの設定の作業により、これまでは困難だった。しかしHiltはボイラープレートコードを生成し、FakeやMockが必要なときにテストに違った設定をセットアップできる。Hiltを使えばこの問題はDaggerでテストを作成することの妨げにならず、実際の依存関係を簡単に利用できる。
実際にどうやってHiltがTestで依存関係を置き換えるかはこちらに書いてあります。 https://qiita.com/takahirom/items/3231edf2a430569b3e9d#testing
他の解決策の欠点
ユニットテストでDaggerを使わない方法はとてもよくある方法である。これは残念なことに大きな欠点があるが、HiltなしでDaggerを利用することの難しさを考えると理解できる。
例えば、Fooクラスをテストしようとする。class Foo @Inject constructor(bar: Bar) { }このケースでDaggerを使わない場合は単にコンストラクタを呼び出すだけ。一見これはとてもシンプルで理解できる、しかしFooのコンストラクタにBarを適応し始めると崩壊し始める。
テストでの直接のインスタンス化はMockを使うことを促進する
以前話した"実際の依存関係を使う"によって、本物のBarクラスをできるだけ使うべき。しかし、どのようにすれば良いだろうか?テストでFooクラスをテストで使うには、これは実際は再起になる: 自分でインスタンス化する必要があるので、Barもインスタンス化する必要があり、Barに依存関係を持っている場合、同様にそれらをインスタンス化する必要がある。深くなりすぎないようにするために、テストのスピードやパフォーマンスのためではなく、たくさんの壊れやすいボイラープレートコードはメンテナンスの問題を起こすため、FakeやMockを使い始める必要がある。これはFakeやMockを使い始めるには良い理由ではない。そして今これをすることを余儀なくされている。
以前に議論したように標準のFakeを利用する方法では、直接のインスタンス化をするメンテナンスの負荷を減らすことができる。しかし、必ずしもシンプルではない。(省略: 同様にFakeBarがClockに依存して、、などFakeも依存関係を管理しなくてはいけなくなる。)これは通常、開発者をMockを使うことを促進する。Mockは依存関係のチェーンによる問題を解決するが、静かに古いままのこされ残されたり、実際のバグを見つけるという全体的な目的でテストを役立たなくするという重大な欠点がある。テスト作成者以外は誰もMockの動作チェックをしないため、時間が経過するとテストが有用なシナリオをテストしなくなる可能性がかなりある。
テストでの直接のインスタンス化は実装の詳細を表現する
直接のインスタンス化は"実装の詳細を表現してはいけない"というプラクティスを破る。なぜなら、その依存関係の詳細のコンストラクタを呼ぶため。Barが
@Inject construcotr
がついている場合、Fooが実装の詳細をリファクタしたりする場合があるので、Barに依存することを知る必要はない。
この点について説明すると、Foo(Bar, Baz)のようにFooがBarやBazといった依存関係を持っていたときに、Daggerではこのパラメーターの順番を変えても何も起こらない。しかし、直接インスタンス化していた場合はテストを変更する必要がある。同様に新しい@Injectクラス
やオプショナルバインディングを追加する場合もプロダクションでは変更する必要がないが、テストでは変更が必要になる。まとめ
Hiltは実際の依存関係を使って簡単にテストを書くために、DaggerをテストでHiltを使うデメリットを治すように設計されている。Hiltを使ったテストはこれらの哲学に従う場合、全般的に良い体験になる。
- 投稿日:2020-09-24T12:49:07+09:00
【Android】Android 11から始めるWireless Debugging
Wireless Debugging
Android11からadbを介したワイヤレスでのアプリのデプロイとデバッグが可能になりました。
そのためUSB接続の必要がなくなりリモートで複数のデバイスにアプリにデプロイがしやすくなりました。設定方法
- AndroidStudioにSDK Platform-Toolsの最新版をインストールする(※30.0.4では確認済み)
- デバッグで利用する端末でDeveloper OptionsをONにする
- Wireless debuggingをONにする
- 表示されるダイアログ内の許可を選択する
- Pair device with pairing codeを選択する
terminalにて[sdk location]/platform-tools へ移動する(※sdk locationはAndroid StudioのProject Structure等で参照)
以下を実行(IP:Portは手順6で覚えた値を代入しその後PairCodeを入力)
~/Library/Android/sdk/platform-tools $ adb pair IP:Port Enter pairing code:
以下が表示されれば成功
Successfully paired to 192.168.1.130:37099 [guid=adb-235XY]
参考資料
https://developer.android.com/about/versions/11/features#wireless-adb