2024年5月7日火曜日

Android Retrofitを使った情報取得する実装を解説

どうも。どっことです。今回は、Retrofitを使った情報取得する実装について解説します。

Retrofitを使った通信処理の実装

他の言語ではいくつか紹介していましたが、そもそもAndroidを紹介していないことに気づきました。そんなわけで今回は、Androidのデファクトスタンダードの一つとなっているRetrofitというライブラリを使った通信処理の実装を解説します。

実装手順

以下の手順で実装していきます。

  • build.gradleにライブラリを追加
  • AndroidManifest.xmに通信するパーミッションを追加
  • Retrofitによる通信処理の実装1
  • 通信するためのIFと、レスポンスデータクラスを追加
  • Retrofitによる通信処理の実装2

順に解説していきます。

build.gradleにライブラリを追加

まずはbuild.gradledependenciesに以下を追加します。

dependencies {
    // moshiライブラリ。Jsonをデータオブジェクトに変換してくれる。
    implementation("com.squareup.moshi:moshi-kotlin:1.15.1")
    // retrofitライブラリ。通信処理してくれるライブラリ。
    implementation("com.squareup.retrofit2:retrofit:2.11.0")
    // moshi-converter。 retrofit で moshi をいい感じに使ってくれるためのもの。
    implementation("com.squareup.retrofit2:converter-moshi:2.11.0")
}

AndroidManifest.xmに通信するパーミッションを追加

アプリ上で外部通信する場合、AndroidManifest.xmlにパーミッションの宣言が必要です。

以下を追加します。

<uses-permission android:name="android.permission.INTERNET" />

Retrofitによる通信処理の実装1

今回利用するAPIとして、サンプルAPIを公開している以下を利用させていただきました。

まずは実際に通信処理をするインスタンスを作るため、Retrofitのインスタンスを生成しましょう。

val retrofit = Retrofit.Builder()
  .baseUrl("https://api.sampleapis.com")
  .addConverterFactory(
      MoshiConverterFactory.create(
          Moshi.Builder()
              .add(KotlinJsonAdapterFactory())
              .build()
      )
  .build()
  • baseUrlは接続先URLのドメインを指定します。パスは後述するインターフェース側に記載します。
  • addConverterFactoryは、通信結果により取得したJsonを解析させるためのライブラリを指定します。今回はMoshiライブラリを指定しています。

用意したretrofitオブジェクトは後ほど利用します。

通信するためのIFと、レスポンスデータクラスを追加

通信するためのインターフェースと、レスポンスデータクラスを追加します。

インターフェースはメソッド(@GET)やretrofitオブジェクトのドメインからのパス(/coffee/hot)を指定し、レスポンスとしてどのようなデータを返却してもらうかを定義します。

interface ApiInterface {
  @GET("/coffee/hot")
  fun hotCoffee(): Call<List<Coffee>>
}

またレスポンスデータとしてCoffeeクラスのリストを定義します。今回は簡単のため、titleだけを解析対象としてデータ定義します。

data class Coffee(val title: String)

他のデータも取得したい場合は、対応するものをメンバ変数に定義すれば解析してくれます。

Retrofitによる通信処理の実装2

先ほど追加したインターフェースを渡して、実際に通信処理してくれるインスタンスを生成しましょう。

val api = retrofit.create(ApiInterface::class.java)

あとは、生成したインスタンスで通信処理を依頼します。enqueue()メソッドで通信処理を非同期に依頼します。

api.hotCoffee().enqueue(object : Callback<List<Coffee>> {
    override fun onResponse(p0: Call<List<Coffee>>, response: Response<List<Coffee>>) {
        Log.d("RetrofitActivity", "response.isSuccessful:${response.isSuccessful}")
        Log.d("RetrofitActivity", "response.code:${response.code()}")
        Log.d("RetrofitActivity", "response.message:${response.message()}")
        Log.d("RetrofitActivity", "response.raw:${response.raw()}")
        Log.d("RetrofitActivity", "response.body:${response.body()}")
    }
    override fun onFailure(p0: Call<List<Coffee>>, error: Throwable) {
      // エラーハンドリング
      Log.w("RetrofitActivity", "onFailure", error)
    }
})

なお同じ通信処理の依頼でexecute()というメソッドがありますが、こちらは同期的に通信処理を依頼します。Androidではメインスレッドで通信処理を実施するとクラッシュしてしまうので、利用するタイミングの検討が必要となります。

まとめ

今回は、Retrofitを使った情報取得する実装について解説しました。通信処理による情報取得・送信はモバイルアプリでは必須な機能となるので、ぜひ参考にしてくださいね。

参考

2024年5月5日日曜日

Android mockito-kotlinを使ったテストコードの書き方を紹介

どうも。どっことです。今回は、mockito-kotlinライブラリを使ったKotlinでの単体テストの書き方を紹介します。

mockito-kotlinを使ったモック化

CI/CDの重要性が注目されて久しいですが、単体テストをはじめとしたテストコードを実装できるエンジニアはまだまだ多くありません。またテストコードは実装経験あるけど、いざ実装しようとした時に「あれってどうやるんだっけ」となるような、テストコードの実装がまだ手に馴染んでいない人も多いかと思います。

今回は単体テストのテストコードを実装する上で必須のテクニックとなるモック化について紹介したいと思います。

モック化とは

他の機能の影響によりテストが不安定な状態となることを防ぐため、あらかじめ固定の値を返したり、特定の振る舞いをさせるように指定しておくことです。

実装方法

以下の順に解説していきます。

  • 使用するライブラリ(mockito-kotlinライブラリの紹介)
  • 導入方法
    • 実装方法

    使用するライブラリ

    オブジェクトをモック化するにあたり、JavaやKotlinではさまざまなモック化ライブラリが公開されています。今回はその中のひとつであるmockito-kotlinを使った導入・実装方法を解説していきます。

    mockito-kotlin

    もともとJavaのモックフレームワークとして利用されているMockitoライブラリを、Kotlinでも簡単に利用できるような機能を具備しているライブラリがmockito-kotlinです。公式ページを参考欄に載せておくので、詳しい情報をお探しの方はそちらを参照してください。

    導入方法

    いつものごとく、build.gradleのdependenciesに追記します。以下を追加してください。

    dependencies {
      testImplementation "org.mockito.kotlin:mockito-kotlin:5.3.1"
    }

    実装方法

    それでは、モック化する実装方法について解説します。

    モック化の実装①戻り値の固定化

    戻り値を固定化する実装は以下です。 mockでモックするクラス、onでモックするメソッドを指定します。そしてdoReturnで戻り値を指定します。

    val mock = mock<Sample> {
        on { sample() } doReturn "sample"
    }

    モック化の実装②例外

    メソッドが呼ばれた時に特定の例外を投げるようなモックの実装は以下です。doThrowで例外を指定します。

    val mock = mock<Sample> {
        on { sample() } doThrow IllegalStateException()
    }

    モック化の実装③振る舞いの指定

    メソッドが呼ばれた時に特定の振る舞いをさせるモックの実装は以下です。doAnswerで具体的な振る舞いを指定します。

    val mock = mock<Sample> {
        on { sample() } doAnswer {
            // do anything.
        }
    }

    まとめ

    今回は、テストコードを実装する上で必要不可欠なテクニックであるモック化をmockito-kotlinライブラリを使って実装する方法について解説しました。他の機能に依存しない疎結合なテストコードを実装するためにモック化は重要なテクニックとなるので、手に馴染むまで何度も実装しましょう。

    参考

    2024年2月1日木曜日

    GitHub draft pull requestを作成する方法を解説

    どうも。どっことです。今回はGitHubにおける draft Pull Requestの手順を記載します。

    GitHubでdraft Pull requestを作成する

    GitHubではPull Request(以下、PR)を作成するとき、ステータスをdraftとして作成することができます。これにより、
    「とりあえずこんな感じで進めてます!見てほしいです!」

    「こんな感じに実装していますがうまく動きません!何かわかりますか?」
    など、チーム内での方向性の補正や問題の共有に利用することができます。

    draft PRの作成方法

    draft PRの作成手順は通常のPRを作成する手順とほぼ同じです。

    1. Pull Requests タブから マージ元/マージ先ブランチを選択し、Create PRをクリックします。
    2. PR作成に必要な項目を入力します。
      • ここまでは通常のPRの作成手順と同じだと思います。
    3. Create pull request▽をクリックしドロップダウンを表示します。その中からCreate a draft pull requestをクリックすることでdraft PRを作成することができます。

    作成後も、draftと通常(read for review)のステータスを切り替えることができます。

    • マージボックスにあるReady for Reviewをクリックすると、レビュー準備完了のステータスにすることができます。
    • Reviewers欄にあるConvert to draftをクリックすると、逆にそのPRのステータスをdraftにすることができます。

    まとめ

    今回はdraft PRの作成方法について解説しました。昨今、Githubをはじめとするソースコードホスティングの利用はエンジニアには必須のスキルとなりました。そのようなサービスの機能を十分に利用することで、開発を効率よく進めていきたいですね。

    参考

    2023年12月22日金曜日

    Mac ホットコーナーをカスタマイズする方法を解説

    どうも。どっことです。今回は、Macのホットコーナーのカスタマイズについて解説します。

    Macのホットコーナーをカスタマイズする

    Macを使っていると右下にカーソルを当てるとクイックメモが表示されますが、ショートカットやアイコンなどの位置によっては、煩わしさを感じる人も多いと思います。私もそのうちのひとりでした。どうにか表示されないようにできないかなと調べたので、紹介します。

    設定方法

    手順は簡単で、Macの設定から以下を設定してあげれば解決します。

    • システム設定 > デスクトップとDock > ホットコーナー > 右下を - に設定

    調べたら、MissionControlも設定することができました。

    • ホットコーナー > 右上を MissionControl に設定

    参考

    2023年12月15日金曜日

    Android ソフトキーボードを閉じる実装について解説

    どうも。どっことです。今回はAndroidでキーボードを閉じる実装を解説します。

    ソフトキーボードを閉じる実装

    以前このブログで、iOSでのキーボードを閉じる実装について解説しました。今回はそのAndroid版です。

    解説

    さっそくサンプルを載せます。InputMethodManagerにアクセスし、キーボードを閉じるようhideSoftInputFromWindowで依頼する、という具合ですね。

    val inputMethodManager = getSystemService(INPUT_METHOD_SERVICE) as? InputMethodManager
    inputMethodManager?.hideSoftInputFromWindow(v.windowToken, 0)
    

    「いうほど難しいか?」と言われればそうでもなさそうですが、
    「キーボード消すの、どのマネージャーに依頼するんだっけ...?」とか
    InputMethodManagerに依頼するのはいいけど、どのメソッドだっけ...?」とか
    「引数には何を渡すんだっけ..」とか、ちょっとした煩わしさが見え隠れしているように感じます。。

    まとめ

    今回はAndroidでソフトウェアキーボードを閉じる実装方法について解説しました。表示されるべき時に表示され、消えるべき時に消えるあるべき姿が、ユーザに良い体験を提供する考え方なので、意識していきましょう。

    Android アプリ内にXMLを組み込む/読み込む実装を解説

    どうも。どっことです。今回は、アプリ内へのXML組み込み/読み込みをする実装について解説します。

    XMLをアプリ内に埋め込む・読み込む

    AndroidのリソースにはXMLを配置することができます。AndroidResourceよりも単純なファイル管理として扱えるので、アプリの共通設定などの管理に利用することができます。

    実際に配置する場所はapp/res/xmlフォルダです。無い場合は新規に追加して、XMLファイルを配置してください。

    例えばsample.xmlを配置した場合、参照する時は以下のようにXMLファイルを指定します。

    val parser : XmlResourceParser = context.resources.getXml(R.xml.sample)

    Android開発ではAndroidResourceがよしなにやってくれるので、XmlResourceParserは使い馴染みのない人が多いかもしれませんが、getEventType()/next()を駆使してIterableのように解析するものです。

    var eventType: Int = parser.getEventType();
    // XMLドキュメントが終了になるまでwhile文を繰り返す
    while (eventType != XmlPullParser.END_DOCUMENT) {
        if(eventType == XmlPullParser.START_DOCUMENT) {
            System.out.println("XMLドキュメントの読み取り開始");
        } else if(eventType == XmlPullParser.START_TAG) {
            System.out.println("新しいタグの参照:"+parser.getName());
        } else if(eventType == XmlPullParser.END_TAG) {
            System.out.println("タグが閉じられた:"+parser.getName());
        } else if(eventType == XmlPullParser.TEXT) {
        // タグに設定されている値を参照
            System.out.println("値:"+parser.getText());
        }
        // 次の要素の参照へ
        eventType = parser.next();
    }

    まとめ

    今回はアプリ内にXMLを組み込み、それを参照する実装方法について解説しました。アプリの設定管理などの1案として挙げられるので、有効活用していきたいですね。

    参考

    Android 現在表示しているActivityやFragmentを確認するコマンドを紹介

    どうも。どっことです。今回は、現在表示しているActivityFragmentを確認するためのコマンドを紹介します。

    表示中のActivity/Fragmentを確認する

    Androidアプリの開発中に「今表示しているActivityFragmentはなんだ...?」と調べる機会があったので、調べた結果を紹介します。

    表示しているActivityやFragmentを確認する

    Activityを確認する

    以下のコマンドで確認できます。

    $ adb shell dumpsys activity top

    Fragmentを確認する

    以下のコマンドで確認できます。

    $ adb shell dumpsys activity top | grep 'Added Fragments' -A 10

    まとめ

    今回は表示しているActivityFragmentを確認するためのコマンドを紹介しました。Android Studioを使っているだけではあまり知る機会のないものですが、開発・デバッグに活かしていきたいですね。

    参考

    groupId,artifactIdについて解説

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

    groupIdとは?

    他のすべてのプロジェクトと区別するためのID。グループを表現したID。一般的にはドメイン名を逆にしたものが挙げられる。例えばcom.exampleなど。自分のWebページなどがあるなら、それを使うのが無難そうです。

    artifactIdとは?

    プロジェクト名という表現がわかりやすい。ライブラリ名とかですね。

    versionとは?

    そのプロジェクトで管理しているバージョン。デフォルトで1.0-SNAPSHOTとなっているが、 フォーマットは決まっていない。

    参考

    2023年12月12日火曜日

    Android テキスト周りの超細かい余白を取得する方法を解説

    余白をテキストのピクセル単位でデザイン要求してくるデザイナー、絶対に許さない。

    解説

    テキストのベースラインから、上の余白(top, ascent)や下の余白(descentやbottom)をピクセル単位で取得することができます。この値を使って、数ピクセル単位の余白のズレも調整することができます。

    val textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
    textPaint.setTextSize(12)
    // FontMetricsの取得
    val fontMetrics : FontMetrics = textPaint.getFontMetrics()
    val topY = fontMetrics.top
    val ascentY = fontMetrics.ascent
    val descentY = fontMetrics.descent
    val bottomY = fontMetrics.bottom

    正直に言います。もう二度とやりたくありません。

    参考

    2023年12月4日月曜日

    Android Kotlin Coroutineを並行に実行する実装を解説

    どうも。どっことです。今回はKotlin Coroutineの並行実行する処理の実装方法について解説していきます。

    Kotlin Coroutineを並列に実行する

    非同期処理をとっても素敵に実装できるKotlin Coroutineですが、いくつかの処理を同時に実行したいようなケースにも対応することができます。APIによる通信やデータベースデータの永続化といった、時間がかかる処理をできるだけ短縮していきましょう。

    実装方法

    実装だけなら以下の2パターンで実現することができます。

    async/awaitによる実装

    ひとつはasync/awaitを使って実装する方法です。

    viewModelScope.launch {
        val apiList = listOf(
            // async でコルーチンを生成 その中でAPIを実行する
            async { api1() },
            async { api2() },
            async { api3() },
        )
        // すべてのコルーチンを実行。全部終わるまで待つ。
        apiList.awaitAll()
    }

    launch/joinAllによる実装

    もうひとつはlaunch/joinAllを使って実装する方法です。

    viewModelScope.launch {
        // lanuch でコルーチンを作成し、その中でAPIを実行する。
        val apiJobsList = listOf(
            launch { api1() },
            launch { api2() },
            launch { api3() },
        )
        // すべてのコルーチンを実行。全部終わるまで待つ。
        apiJobsList.joinAll()
    }

    まとめ

    今回は、Kotlin Coroutineによる処理を並列実行する実装について解説しました。ユーザの待ち時間を減らせるように活用していただけると幸いです。

    参考

    移行予定

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