2025年4月2日水曜日

Blogger 自分のアクセスを追跡しない設定を紹介

どうも。どっことです。今回はBloggerで自分のアクセスを追跡しない設定を紹介します。

自分のアクセスを追跡しない

完全に自分自身の備忘録のためだけのページです。参考ページの方、とても助かっています。本当にありがとうございます。

1. 以下をコピーする。日付は適当。

document.cookie = "_ns=2; expires=Tue, 19 Jan 2038 03:14:07 GMT; path=/";

2. F12をして developer tools を表示する。

3. Consoleタブをクリックする。

4. コピーした文字列を貼り付けて実行する。

まとめ

以上です。

参考

2025年3月30日日曜日

Android Studio VCS Operations Popupをカスタマイズする方法を解説

どうも。どっことです。今回はAndroid StudioにあるVCS Operations Popupにカスタマイズ方法ついて解説します。

VCS Operations Popopとは

VCS Operations PopupはAndroid Studioでバージョン管理ツールの操作するときのポップアップです。control+vのショートカットで表示することができます。メニューから操作する手間が省けるので、多用している人もいるかと思いますが、今回はこのポップアップをカスタマイズする方法を解説します。

VCS Operations Popopのカスタマイズ

カスタマイズですが、実はAndroid Studioがカスタマイズするための設定項目を用意してくれています。なので謎の設定ファイルの書き換えや、ターミナルなどでの謎のコマンド操作は不要です。(地味に嬉しい)

Android StudioのSettings | Appearance & Behavior | Menus and Toolbarsにアクセスしてください。プロジェクトにGitを利用している場合は以下のようなポップアップが表示されると思います。

この画面で項目をカスタマイズすることができます。一覧の中にあるVCS Operations PopupからVCS.Operations.Popup.VcsAwareを選択している状態で+ボタンをクリックしましょう。

ここから項目を追加することができます。たとえば、Update projectをリストに追加してみましょう。一覧からUpdate projectを探してOKをクリックしてください。それで完了です。

それではVCS Operations Popupを表示してみましょう。control+vを入力すると...


追加したUpdate projectがポップアップに追加されていることを確認できました!これでいちいちVCSメニューまでマウス移動させる手間が省けますね!

まとめ

今回はAndroid StudioにあるVCS Operations Popupのカスタマイズ方法について解説しました。Android Studioや、そのベースとなっているIntellij IDEAでは、このポップアップに限らず、さまざまな項目をカスタマイズする設定画面を提供しているので、作業効率がより良くなるようどんどんカスタマイズしていきたいですね。

参考

2025年3月29日土曜日

GitHub ライブラリをGithubに公開する方法を解説(GitHub Packages)

どうも。どっことです。今回はGitHub Packagesを使って自作ライブラリを簡単に公開する方法を解説したいと思います。

プライベートで資格試験などに向けた問題集アプリを不定期に作るのですが、毎回データクラスや画面を一から作っているので「そろそろ標準化しよう。。。」と思いました。ただ標準化したはいいものの、いい感じに使い回すためにはどうしたらいいか、というところで調べた結果、GitHub Packagesのサービスに行き着いたので今回はこちらを紹介し、実際に公開する方法を解説したいと思います。

GitHubPackagesとは

GitHubPackagesはGitHubのサービスの一つで、まさに今回のようなライブラリや、パッケージなどを共有するためのものだそうです。mavenやnpm、NuGetなどの形式で公開することができます。しかも嬉しいことに公開範囲も指定できるようで、一般公開からプライベートやTeam限定など、制御することができるとのこと。とても便利。

今回はJava向けのライブラリを公開するために、Gradleプラグインを使った手順を紹介したいと思います。

GitHubPackagesにライブラリを公開する設定手順

以下の手順で進めます。

  1. app/build.gradleに設定を追加する。
  2. Gradleタスクを実行する。
  3. (任意)GitHub Actionで自動的に更新する。

順番に解説していきます。

app/build.gradleに設定を追加する

app/build.gradleに以下を追加します。

plugins {
  ...
  id 'maven-publish'
}

publishing {
  ...

  repositories {
    maven {
      name = "GitHubPackages"
      url = "https://maven.pkg.github.com/mkt120/sample_repository"
      credentials {
        username = System.getenv("USER_NAME")
        password = System.getenv("ACCESS_TOKEN")
      }
    }
  }
}
  • pluginmaven-publishを追加。ライブラリ公開を簡単に実行してくれるプラグインを組み込む。
  • urlはGitHubのリポジトリURL。
    • GitHubのリポジトリに対応したURLを設定。
  • usernamepasswordはログイン情報。
    • 特にpasswordはログインパスワードだと警告orエラーが発生するので、Githubからアクセストークンを取得しそれを設定する。直書きだとセキュリティ観点でリスクがあるので、Githubの secret and variables に設定しておいて、それを参照するようにしておくのが無難。

Gradleタスクを実行する

前項の設定を追加し、sync gradle を実行すると以下のタスクが追加されます。

publishGprPublicationToGitHubPackagesRepository

これをコマンドラインやGradleペインから実行することで、 GithubPackagesへの登録が行われます。

./gradlew publishGprPublicationToGitHubPackagesRepository

(GithubPackageによると)以下のタスクはGithubPackagesへの登録だけでなく、その前段階のライブラリのビルドなども一緒に実行してくれるようなので、こちらを利用するのが良さそうです。

./gradlew publish

(任意)GitHub Actionで自動的に更新する

ここまでだけでGitHubPackagesにパッケージを登録することができますが、GitHubにコミットをプッシュしたことを契機に、GitHubPackagesに更新を入れるようGitHub Actionで自動登録できるようにしておきます。

#masterブランチにプッシュされたら実行
on:
  push:
    branches: [ "master" ]
  ...

jobs:
  build:
  ...
  
  # name. githubAction のコンソール上で実行内容がわかりやすいように名前付けしておく
  - name: publish library 
    run: ./gradlew publish
    env:
      USER_NAME: ${{ secrets.USER_NAME }}
      ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}

まとめ

今回はGitHubPackagesにライブラリを公開する方法を解説しました。似たようなデータ形式・UIのアプリケーションをたくさん開発している方は、こういった機能を活用することで開発作業の効率化を図りたいですね。また、ライブラリ化したはいいけど、maven repository に登録するほどのものではないんだよなぁ...という方にも、GitHubPackagesという公開範囲を管理できる領域に登録することで適切にスケーリングすることもできるのではないかと思います。

参考

2025年3月22日土曜日

Android/Jetpack Compose Imageに関するパラメータを紹介

どうも。どっことです。今回はJetpack ComposeのImageコンポーサブルについてチートシートを紹介したいと思います。

Imageコンポーサブルとは

Imageコンポーサブルは、名前の通り画像やイメージを表示するコンポーサブルです。まずはAndroidViewのImageViewで実装していたことが、Jetpack Composeでも同様に実現できるのかが気になるところですが、結局ImageViewで重要な設定であったscaleType、つまりイメージの見せ方についての設定がそれに相当するcontentScaleで実現でき、それ以外はModifierを使えば済んでしまうようです。(つまりImageに関する紹介がほとんどない...)

このページではscaleTypeに相当するcontentScaleについて軽く触れ、その設定がどのような見え方をするのかは公式サイトの方にお任せしようと思います。

Imageコンポーサブルを使うときのパラメータチートシート

まずは、必要最小限で設定できるImageのパラメータです。

Image(
  painter = painterResource(id = R.drawable.dog), // リソースから画像表示
  contentDescription = stringResource(id = R.string.dog_content_description) // 説明文
)

contentScale

contentScaleにはいくつかの設定項目があるので、一覧で紹介します。

  • ContentScale.Fit
    • アスペクト比を維持しながら拡大・縮小
    • scaleTypeのfitCenter相当
  • ContentScale.Crop
    • 空きスペースがなくなるように画像を拡大表示(くり抜き)
  • ContentScale.FillHeight
    • アスペクト比を維持しながら、高さに合わせて拡大・縮小
  • ContentScale.FillWidth
    • アスペクト比を維持しながら、幅に合わせて拡大・縮小
  • ContentScale.FillBounds
    • Viewの大きさに合わせて拡大・縮小(画像が歪む)
    • scaleTypeのfitXY相当
  • ContentScale.Inside
    • アスペクト比を維持しながら、縮小(拡大はしない)
  • ContentScale.None
    • 画像に対して何もしない
    • scaleTypeのcenter相当

まとめ

今回はImageコンポーサブルについて紹介しました。正直Image自体には目新しいパラメータがなかったので、contentScaleに関する紹介程度となりましたが、アプリ開発においてイメージの表示は必須機能なので、contentScaleのパラメータについては理解を進ませておきたいところです。

参考


2025年2月22日土曜日

Android/Jetpack Compose Modifierに関するパラメータを紹介

どうも。どっことです。今回はJetpack ComposeのModifierについてチートシートを紹介したいと思います。

前回はTextコンポーサブルを紹介しましたが、「そもそも共通で設定するパラメータってどこで管理するねん」となりまして、調べたらModifierというオブジェクトがあることがわかりました。 今回はこのModifierについて、チートシートとして紹介したいと思います。

Modifierオブジェクトとは

Modifierは、コンポーサブルに対して設定可能な共通のパラメータを管理しているオブジェクトです。 AndroidViewがわかる人なら、Viewに対して設定できる項目くらいの理解で問題ないと思います。

Modifierを使うときのパラメータチートシート

Modifierで設定できるパラメータは(よく使うものは)以下です。

    // ****** 横幅指定関連 ****** // 
Modifier.width(20.dp)                    // 幅指定(layout_width)
    .fillMaxWidth()                      // 幅いっぱい(layout_width="match_parent")
    .widthIn(20.dp, 20.dp)               // 最小・最大幅指定(minWidth,maxWidth)

    //****** 高さ指定関連 ******//
    .height(20.dp)                       // 高さ指定(layout_height)
    .fillMaxHeight()                     // 高さいっぱい(layout_height="match_parent")
    .heightIn(20.dp, 20.dp)              // 最小・最大高さ指定(minHeight, maxHeight)
    
    //****** 縦横まとめて指定 ******//
    .size(20.dp)                         // 縦横指定(layout_width,layout_height) 
    .size(20.dp, 20.dp)                  // 縦横指定(layout_width,layout_height) 
    .fillMaxSize()                       // 縦横幅いっぱい (layout_width="match_parent"/layout_height="match_parent")
    .sizeIn(20.dp, 20.dp, 50.dp, 50.dp)  // 最小・最大縦横指定(minWidth, minHeight, maxWidth, maxHeight) 
    
    //****** background関連 ******//
    .background(Color.Red)               // 背景色指定(background)
    
    //****** padding関連 ******//
    .padding(top = 10.dp)                // 上部余白 (paddingTop)
    .padding(start = 10.dp)              // 左余白 (paddingStart)
    .padding(end = 10.dp)                // 右余白 (paddingEnd)
    .padding(bottom = 10.dp)             // 下部余白 (paddingBottom)
    .padding(horizontal = 10.dp)         // 左右余白 (paddingHorizontal)
    .padding(vertical = 10.dp)           // 上下余白 (paddingVertical)
    .padding(10.dp)                      // 上下左右余白 (padding)
    
    //****** 位置調整関連 ******//
    .align(Alignment.CenterHorizontally) // layout_gravity(左右位置, Columnコンポーネント内などで)
    .align(Alignment.CenterVertically)   // layout_gravity(上下位置, Rowコンポーネント内などで)
    
    //****** タップ処理関連 ******//
    .clickable { /** */ }                // タップ処理(setOnClickListener)
    
    //****** 枠線関連 ******//
    .border(BorderStroke(3.dp, Color.Blue)) // 枠線をつける(witdh, color)

    //****** 角丸関連 ******//
    .background(Color.Red, RoundedCornerShape(10.dp))                  // 角丸背景にする
    .border(BorderStroke(3.dp, Color.Blue), RoundedCornerShape(10.dp)) // 角丸枠線をつけるそ

その他

dimens.xmlに定義した値をpadding/marginの値として使いたい

dimensionResourceを使えばリソース定義を参照できます。以下、参考ページから転記。

// In the res/values/dimens.xml file
// <dimen name="padding_small">8dp</dimen>
// In your Compose code
val smallPadding = dimensionResource(R.dimen.padding_small)
Text(
    text = "...",
    modifier = Modifier.padding(smallPadding)
)

まとめ

今回はModifierオブジェクトで設定できるパラメータについてチートシートとして紹介しました。目を通してみると、角丸の実装がサポートされるようになったのは非常に嬉しいポイントだと思いました。この記事も参考になりそうな項目を見つけたら随時更新していく予定ですので、参考にしていただけますと幸いです。

次回やるとしたら、Imageコンポーネントについて同様に紹介しようと思います。

参考

2025年2月15日土曜日

Android/Jetpack Compose Textに関するパラメータを紹介

どうも。どっことです。今回はJetpack ComposeのTextコンポーサブルについてチートシートを紹介したいと思います。

これまでのAndroidViewから、Jetpack Composeに移行が完了できた人も少なくないのではないでしょうか。私はそんな移行できていない人間の一人なのですが、今回はそんなJetpack Composeで画面を実装する時に「これってどうやって実装するんだっけ!?」となってもすぐに解決できるよう、チートシートとしてこのページに整理したいと思います。

Textコンポーサブルとは

Textコンポーサブルは、AndroidViewでいうところのTextView、つまりキホンのキですね。テキストを表示せずにアプリを作ることはできないので、まずはここから入るのが王道だと思います。

Textコンポーサブルをつかうときのパラメータチートシート

Textコンポーサブルに設定できるパラメータは(よく使うものは)以下です。

Text(
  "Hello World", 
  fontSize = 24.sp,    // テキストサイズ
  lineHeight = 30.sp,  // 行の高さ
  maxLine = 3,         // 最大行数
  minLine = 1,         // 最小行数
  color = Color.Red,   // テキスト色
  fontStyle = FontStyle.Italic, // テキストスタイル(斜体)
  fontWeight = FontWeight.Bold, // テキストスタイル(太字)
  textAlign = TextAlign.Center, // テキストの位置(gravity)
  overflow = TextOverflow.Ellpsis // テキストが収まらない場合の省略表示(ellipsize)
)

その他の使い方

リソースを参照してテキストを表示する

stringResourceを利用すると、リソースのテキストを参照できます。

Text(stringResource(R.string.app_name))

表示テキストを装飾する

buildAnnotatedStringを利用すると、装飾されたテキストを表示することができるらしいです。

今回は割愛。

まとめ

今回はTextコンポーサブルでよく使うであろうパラメータについて紹介しました。AndroidViewがDeprecatedになる前にJetpackComposeを身につけておきたいですね。

2025年1月4日土曜日

Android GridLayoutの使い方について解説

どうも。どっことです。今回はGridLayoutの使い方について解説します。

GridLayout

Androidのレイアウトを実装するとき、LinearLayoutやConstraintLayoutをよく利用しますが、Viewを格子状に配置する時はGridLayoutが便利です。 LinearLayoutを複数用意しなくても済みますし、ConstraintLayoutで必要なたくさんの属性値を設定しなくても済みます。また、一部のLayoutParam属性に初期値が設定されているので、実際に実装する時の設定項目が少なく済むのも良いところの一つかと思います。今回はそんなGridLayoutの使い方について解説します。

GridLayoutの使い方

今回は、レイアウトファイルでGridLayoutを利用する場合の実装を解説します。

<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:columnCount="3"
    android:background="@android:color/holo_red_light"
    android:rowCount="1">

    <TextView
        android:layout_row="0"
        android:layout_column="0"
        android:padding="10dp"
        android:background="@android:color/holo_blue_bright"
        android:text="00" />
    <TextView
        android:layout_row="0"
        android:layout_column="1"
        android:padding="10dp"
        android:background="@android:color/holo_blue_dark"
        android:text="01" />
    <TextView
        android:layout_row="0"
        android:layout_column="2"
        android:padding="10dp"
        android:background="@android:color/holo_green_light"
        android:text="02" />
</GridLayout>
  1. GridLayout
    1. layout_width:match_content指定。画面幅いっぱい指定。
    2. layout_height:wrap_content指定。必要最小限の高さ指定。
    3. layout_row:1、layout_column:3をそれぞれ指定。1行3列の格子指定。
  2. GridLayout内の子View
    1. layout_width/layout_heightを指定していない。
      • これはGridLayoutが初期値としてwrap_contentを設定しているため。
    2. layout_columnlayout_rowにはそれぞれの配置位置を指定。

この実装でそのままレイアウトを確認すると、以下が表示されます。

GridLayout内のTextViewが全て左寄せに表示されました。子Viewに大きさを指定していないので、当たり前といったら当たり前ですね。

LinearLayoutのlayout_weightのように、要素を均等に広げるためには、layout_columnWeightlayout_rowWeightを使います。今回は横幅を均等に広げるため、layout_columnWeightを使います。

<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@android:color/holo_red_light"
    android:columnCount="3"
    android:rowCount="1">

    <TextView
        android:layout_row="0"
        android:layout_column="0"
        android:layout_columnWeight="1"
        android:background="@android:color/holo_blue_bright"
        android:padding="10dp"
        android:text="00" />

    <TextView
        android:layout_row="0"
        android:layout_column="1"
        android:layout_columnWeight="1"
        android:background="@android:color/holo_blue_dark"
        android:padding="10dp"
        android:text="01" />

    <TextView
        android:layout_row="0"
        android:layout_column="2"
        android:layout_columnWeight="1"
        android:background="@android:color/holo_green_light"
        android:padding="10dp"
        android:text="02" />
</GridLayout>

これでレイアウトを表示すると以下になります。

均等幅に表示されました。

layout_rowWeightも同様です。上のケースは、GridLayoutの高さ(layout_height)がwrap_content指定になっているため、100dp指定に変更して試してみます。

まずは、何も指定せずに表示を確認します。

<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="100dp"
    android:background="@android:color/holo_red_light"
    android:columnCount="1"
    android:rowCount="2">

    <TextView
        android:layout_row="0"
        android:layout_column="0"
        android:background="@android:color/holo_blue_bright"
        android:padding="10dp"
        android:text="00" />

    <TextView
        android:layout_row="1"
        android:layout_column="0"
        android:background="@android:color/holo_green_light"
        android:padding="10dp"
        android:text="10" />

</GridLayout>

これでレイアウトを確認すると以下になります。

layout_columnWeightの時と同様、上寄せに要素が表示されました。layout_rowWeightを指定してみましょう。

<?xml version="1.0" encoding="utf-8"?>
<GridLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content"
    android:layout_height="100dp"
    android:background="@android:color/holo_red_light"
    android:columnCount="1"
    android:rowCount="2">

    <TextView
        android:layout_row="0"
        android:layout_rowWeight="1"
        android:layout_column="0"
        android:background="@android:color/holo_blue_bright"
        android:padding="10dp"
        android:text="00" />

    <TextView
        android:layout_row="1"
        android:layout_rowWeight="1"
        android:layout_column="0"
        android:background="@android:color/holo_green_light"
        android:padding="10dp"
        android:text="10" />

</GridLayout>

これでレイアウトの表示確認をすると以下になります。

子Viewが均等な高さで表示されました。

まとめ

今回はGridLayoutの使い方について解説しました。LinearLayoutやConstraintLayoutで大抵のことは実現できてしまうところではありますが、実はGridLayoutもうまく使えば同じように便利に利用することができます。実はGridLayoutだと、LinearLayoutでよく困るアレを解決することができるのですが...これは別の記事で紹介したいと思います。

参考

2024年11月4日月曜日

Android 追加読み込みListViewを実装する方法を解説

どうも。どっことです。今回はListViewに追加読み込みする機能を実装する方法について解説します。

追加読み込み機能を持つListView

またまた、いにしえのListViewに関する解説です。RecyclerViewはカスタマイズ性に長けていますが、「単に一覧で表示してくれればいい」程度であれば、シンプル実装できるListViewもまだまだ使い道のあるコンポーネントかと思います。今回はそんなListViewで、追加読み込みをする機能の実装について解説しようと思います。

追加読み込みListViewを実装する

実装手順は以下の通りです。

  1. 読み込み表示Viewを実装する
  2. 読み込み表示Viewを表示する
  3. 読み込み処理タイミングを検知する

順番に解説していきます。

読み込み表示Viewを実装する

まずは読み込み表示用のViewを実装します。一般的にはプログレスを表示する形かと思いますので、そのViewを用意しておきます。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="50dp">

    <ProgressBar
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</FrameLayout>

読み込み表示Viewを表示する

次に読み込み表示用Viewの表示処理を実装します。ListViewにはFooterViewとしてViewを追加することができるので、ここに読み込み表示Viewを設定します。

listView.addFooterView(createFooterView())
fun createFooterView(): View {
    return layoutInflater.inflate(R.layout.view_progress, null)
}

読み込み処理タイミングを検知する

読み込み処理を実装します。OnScrollListener#onScrollを使って、スクロールが最下部に来た時を検知し、読み込み処理を実施します。

listView.setOnScrollListener(object : OnScrollListener {
    override fun onScrollStateChanged(view: AbsListView?, scrollState: Int) {
        // ここでは気にしない
    }
    override fun onScroll(view: AbsListView?, firstVisibleItem: Int,visibleItemCount: Int, totalItemCount: Int) {
        if (totalItemCount == firstVisibleItem + visibleItemCount) {
            // todo:すべての要素が表示されたので、追加読み込みを処理する
        }
    }
}

onScrollStateChangedが気になる人は、判定処理をあらかじめ実装したinterfaceを定義して、そちらを渡すような実装としても良いかもしれません。

interface OnBottomScrolledListener : OnScrollListener {
    /**
     * 最下部までスクロールされたことを検知
     **/
    fun onScrolledToBottom()

    override fun onScrollStateChanged(view: AbsListView?, scrollState: Int) {
        // ここでは気にしない
    }
    override fun onScroll(view: AbsListView?, firstVisibleItem: Int, visibleItemCount: Int, totalItemCount: Int) {
        if (totalItemCount == firstVisibleItem + visibleItemCount) {
            onScrolledToBottom()
        }
    }
}
listView.setOnScrollListener(object : OnBottomScrolledListener {
    override fun onScrolledToBottom() {
        // 最下部までスクロールされたことを検知したので、追加読み込みする
    }
}

また「読み込んだ結果、追加分が0件だった」場合に再度読み込み処理が実施されないよう、フラグなどでの管理も入れておきます。

listView.setOnScrollListener(object : OnBottomScrolledListener {
    override fun onScrolledToBottom() {
        if (!isLoadNecessary) {
            // 何もせず終了
            // このタイミングで読み込み表示Viewも消しておきましょう
            listView.addFooterView(null)
            return
        }
        // 最下部までスクロールされたことを検知したので、追加読み込みする
    }
}

まとめ

今回は下スクロールしたら追加読み込みしてくれるListViewについて解説しました。前回の解説でもコメントしましたが、RecyclerViewの登場によりListViewはもはやいにしえのコンポーネントとなっていますが、やはり初期装備が揃ってくれているおかげで実装が簡単という点がAndroidエンジニア初心者には優しいですね。

参考

2024年11月1日金曜日

Android 久しぶりにzxing-android-embedded を使ってみたので紹介

どうも。どっことです。今回はzxingを使ってみたので紹介します。

zxingを使ってQRコード/バーコードリーダーを実装する

一時期流行りましたよね。バーコードとか、 QRコードとか読み取って、いい感じになにかやること。ネイティブアプリで。そんな時に、今回使用したzxingというライブラリが非常に使いやすく、何度も私を助けてくれました。今回は、久しぶりにこのライブラリを使ってQRコード読み取り画面を実装してみたので紹介したいと思います。(最近はAndroid標準のカメラがいろいろ読み取ってくれるからもう出番ないんだよなぁ。。。

zxingの組み込みと実装の手順

ライブラリの追加(app/build.gradleに追記)

ライブラリを追加するので、例の如くapp/build.gradledependenciesに以下を追加します。

dependencies {
  implementation 'com.journeyapps:zxing-android-embedded:4.3.0'
}

AndroidManifest.xmlに追記

今回はライブラリ側で「この制御をいれてね」という案内があるのでそれに従います。

<application android:hardwareAccelerated="true" ... >

実装

ハードウェア(カメラ)の制御や、読み取った時の解析はすべてzxing側でやってくれるので、アプリ側からは呼び出す箇所と、読み取り結果を受け取るところだけを実装すればOKです。こちらも例の如くActivityResultLauncherを使ってライブラリの画面を呼び出し・読み取り結果を制御します。

private final ActivityResultLauncher<ScanOptions> barcodeLauncher = registerForActivityResult(new ScanContract(),result -> {
    if(result.getContents() == null) {
        Toast.makeText(this, "Cancelled", Toast.LENGTH_LONG).show()
    } else {
        Toast.makeText(this, "Scanned: " + result.getContents(), Toast.LENGTH_LONG).show()
    }
})
public void launch(View view) {
    barcodeLauncher.launch(new ScanOptions())
}

まとめ

今回はzxing-androidを使ってみたということで紹介しました。標準の機能が便利すぎるとはいえ、まだまだ使い所はあるかと思いますので、是非参考にしていただければと思います。

参考

2024年7月6日土曜日

Android テストコードの実装について解説

どうも。どっことです。今回は、テストコードの実装について解説したいと思います。

テストコード

テストコードは実機やエミュレータに開発段階のアプリをインストールせずとも、プログラムとしてテストを実行できるようにするものです。テストコードを実装せずとも、世の中に公開するアプリを開発することができるので、より難しい機能の実装や複雑なドメインロジックをプログラムに落とし込むなどのスキルを優先して獲得するというロードマップも考えとしてはあると思います。

ただ、昨今のCI/CDの重要性の高まりを鑑みると、テストコードを実装できることもエンジニアとして必要なスキルとして需要が上がってきているように見受けられます。そしてそんな需要が高まっている一方で、テストコードを実装できるエンジニアはまだまだ多くありません。ぜひテストコードを実装できるようになり、より広い知見をもつエンジニアへと一歩を進めましょう。

説明に入る前に(テストコードの種類)

Androidの開発においては、大きく2種類のテストコードがあります。

ユニットテスト

開発PC上で実行されるテストコードです。Androidの機能に依存しないビジネスロジックやアプリケーションロジックに対するテストコードを実装する際のものとなります。開発PC上で実行されるため、後述のインストルメントテストよりも高速に実行・実施ができます。

インストルメントテスト

実機やエミュレーター上で実行されるテストコードです。こちらは、Androidの機能に依存するUIまわりのテストや、外部機能などとの連携に対するテストコードとなります。より現実に近い環境でのテストとなるため、ユーザーストーリーを意識したテストに向いています。一方で、インストールなどのステップがビルド時に含まれるため、実行時間が比較的遅めになります。

今回は、ユニットテストの実装方法について解説します。

ユニットテストを実装する

ユニットテストの実装方法について、以下の流れで説明します。

  • ライブラリの準備
  • 実装
  • その他
    • Robolecticの紹介

ライブラリの準備

ユニットテストのテストコードを実装するためには以下をbuild.gradleに追加が必要です。プロジェクトを新規作成する際にAndroid Studioが自動で追加している場合がありますので、追加が必要か確認してください。

dependencies {
    testImplementation("junit:junit:4.13.2")
}

実装

それでは実装していきましょう。

テスト対象

テスト対象は以下のクラス・メソッドとします。

class Sample {
   fun test(input: Int?): Boolean {
       if (input == null) {
           throw IllegalArgumentException()
       }
       return input > 0
    }
}

テスト観点

テスト対象となるメソッドは、以下の観点でテストコードを実装することができます。

  • trueが返される確認テスト
  • falseが返される確認テスト
  • 例外が投げられるテスト

上をベースに確認するテストコードを追加していきましょう。

テストクラスを追加する

テストを実装するため、テストクラスを実装します。テスト対象のクラスで option + Enter からCreate Testを選択すればテストクラスを作成できます。SampleTestという名前にすると、testディレクトリに以下のようなクラスが作成できると思います。

class SampleTest {
}

trueが返される確認テストを実装する

まずはtrueが返されることのテストです。

@Test
fun testTrue() {
    val sample = Sample()
    val value = sample.test(1)
    Assert.assertEquals(value, true)
}

以降の実装も同様ですが、テストメソッドを実装し@Testアノテーションを付与します。

そして、実際にテストしたい内容を実装します。今回は、入力値に1以上を指定した場合はtrueが返却されるので、それを確認するためのテストを実装します。

falseが返される確認テストを実装する

次にfalseが返されることのテストです。

@Test
fun testFalse() {
    val sample = Sample()
    val value = sample.test(0)
    Assert.assertEquals(value, false)
}

同様に、falseが返却されるケースを実装します。入力値に0以下を指定した場合はfalseが返却されるので、それを確認するためのテストを実装します。

例外が投げられるテストを実装する

そして、例外が投げられることのテストです。

@Test(expected = IllegalArgumentException::class)
fun testException() {
    val sample = Sample()
    sample.test(null)
    Assert.fail()
}

例外が発生するテストは@Testアノテーションのパラメータexpectedを指定します。そのパラメータには発生する例外のクラスを指定します。

また、例外が発生しなかった場合がテストがNGとなるように、例外がthrowされる直後のタイミングでAssert.fail()を実装しておきます。

これにて、該当クラスメソッドのテストが実装できました。あとはテストを実行すれば期待した結果になるかを確認する処理が実行されます。

その他

ここまでテストコードの実装について解説しましたが、実は1点問題があります。ユニットテストは開発PC上で実行されますが、その都合により、AndroidSDKに含まれる機能を利用することができません。これが結構ネックになり、例えばよくある実装の一つであるFragmentのインスタンス生成メソッドは、Fragmentやそれに渡すBundleがAndroidSDKに含まれるものなので、テストコードを実装することができません。

ではどうするかというと、一つはインストルメントテストで実装することです。実機やエミュレーター上でテストすることで、テストコードを実行することができます。

もう一つはRobolectricを利用することです。RobolectricはユニットテストでもAndroidSDKに含まれる機能を利用することができます。

Robolectricの紹介

今回は説明を省略しますが、公式サイトを紹介します。またRobolectricの利用方法についても、後日解説を予定しています。

まとめ

今回はテストコード、特にユニットテストの実装方法について解説しました。テストコードやその実装の重要性は今後も高いものと予想されるので、今後もこれをテーマとした投稿をしていこうと考えていますので、よろしくお願いします。

参考

移行予定

どうも。どっことです。 タイトルの通りですが、諸事情により GitHubPage に移行予定です。 https://mkt120.github.io/ この備忘録に記載の内容を転記しつつ、今後はこちらのページを更新していく予定です。