Kotlin」タグアーカイブ

KotlinでToastをカスタマイズする

先日、ポップアップアラームという設定した時刻にポップアップを表示するアプリを作りました。このページではその中でもポップアップであるToastをカスタマイズして表示する処理について紹介します。

標準のToastを表示する

標準のToastは以下のコードで表示できます。

object ToastView {
    fun showToast(context: Context, message: String) {
        Toast.makeText(context, message, Toast.LENGTH_LONG).show()
    }
}

Toastをカスタマイズする

前述のような標準のToastだと目立たず、通知を見逃しやすいので、上の画像のようにToastのサイズやフォントサイズが大きい独自のレイアウトを作成します。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:ads="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:weightSum="1">

    <TextView
        android:id="@+id/message"
        android:layout_width="320dp"
        android:layout_height="80dp"
        android:background="@drawable/toast_shape"
        android:gravity="center"
        android:paddingLeft="10dp"
        android:paddingRight="10dp"
        android:textColor="@color/colorBase"
        android:textSize="40sp" />

</LinearLayout>

上記の独自レイアウトを表示します。

object ToastView {
    fun showToast(context: Context, message: String) {
        val inflate = context.getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater
        val view = inflate.inflate(R.layout.toast, null)
        val textView = view.findViewById(R.id.message) as TextView
        textView.text = text

        Toast(context).run {
            this.view = view
            duration = Toast.LENGTH_LONG
            setGravity(Gravity.BOTTOM, 0, 250)
            show()
        }
    }
}

KotlinでAndroidの時刻を検知する

先日、ポップアップアラームという設定した時刻にポップアップを表示するアプリを作りました。このページではその中でも時刻の検知の処理について紹介します。

アラームを開始、停止する

Androidアプリで、ある時刻になったら処理を実行したい場合、AlarmManagerを使用します。厳密には、ある時刻になったことを通知するのではなく、ある時間を経過したことを通知できます。
今回はアラームアプリなので、ある程度正確な時間を通知できるsetExact()を呼びます。通知はBroadcastReceiverで受け取ります。
以下のクラスでは、アラームを開始して1度だけ通知します。別のアラームがすでに実行中なら、実行中のアラームは停止し、新しいアラームが開始されます。

object OnceAlarmManager {
    private const val REQUEST_CODE = 0
    private var alarmManager: AlarmManager? = null
    private var pendingIntent: PendingIntent? = null

    fun startAlarm(context: Context, calendar: Calendar) {
        alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
        val intent = Intent(context, AlarmBroadcastReceiver::class.java)
        pendingIntent = PendingIntent.getBroadcast(
                context, REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT)
        alarmManager?.setExact(AlarmManager.RTC, calendar.timeInMillis, pendingIntent)
    }

    fun stopAlarm() {
        alarmManager?.cancel(pendingIntent)
    }
}

アラームアプリでは、1つのアラームで時刻通知したら次のアラームを開始する必要があるので、以下の通り、設定がONになっているアラームを開始します。

object WeeklyAlarmManager {
    fun startNextAlarm(context: Context) {
        var weeklyAlarms = WeeklyAlarmDataManager.weeklyAlarms
        if (WeeklyAlarmUtil.hasPowerOn(weeklyAlarms)) {
            val calendar = WeeklyAlarmUtil.getNextAlarmAsCalendar(weeklyAlarms)
            OnceAlarmManager.startAlarm(context, calendar)
        } else {
            OnceAlarmManager.stopAlarm()
        }
    }
}

アラーム通知を受け取る

前述の通り、BroadcastReceiverでアラーム通知を受け取ります。通知を受け取ったら、ポップアップを表示し、次のアラームを開始します。

class AlarmBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        // Show popup.
        WeeklyAlarmManager.startNextAlarm(context)
    }
}

BroadcastReceiverをアプリに登録します。

<application
    ...
    <receiver android:name=".AlarmBroadcastReceiver">
    </receiver>
</application>

端末の再起動時やタイムゾーンの変更時に、アラームを再設定する

端末が再起動されたことやタイムゾーンが変更されたことを、BroadcastReceiverで受け取れるよう、actionを設定します。

<application
    ...
    <receiver android:name=".AlarmBroadcastReceiver">
        <intent-filter>
            <action android:name="android.intent.action.BOOT_COMPLETED" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.TIMEZONE_CHANGED" />
            <action android:name="android.intent.action.TIME_SET" />
            <action android:name="android.intent.action.DATE_CHANGED" />
        </intent-filter>
        <intent-filter>
            <action android:name="android.intent.action.PACKAGE_REPLACED" />
            <data
                android:path="com.isolity.toastalarm"
                android:scheme="package" />
        </intent-filter>
    </receiver>
</application>

上記で設定したactionの通知時にも、BroadcastReceiverのonReceive()が実行されます。アラーム通知の場合のみ(ここではactionがnullのとき)、ポップアップメッセージを表示します。

class AlarmBroadcastReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        if (intent.action == null) {
            // Show popup.
        }
        WeeklyAlarmManager.startNextAlarm(context)
    }
}

改善点

上記コードの改善点として、例えば、アラーム通知の判定がaction==nullだとわかりにくいので、アクション名つけた方がいいですね。あとはDIとかテストの方法はこれから調べます。

※Huaweiのスマホでの注意事項

Huaweiのスマホでは、以下の設定をしないと、アプリをKillしたあとにAlarmManagerの処理が止まってしまい、通知を受け取れなくなってしまいます。
設定 > 詳細設定 > バッテリーマネージャー > 保護されたアプリ > 対象のアプリをONにする
アプリごとに設定が必要なので、アプリを初めてインストールしたときに設定しておきます。僕はHuaweiのP8liteというスマホを使っていて、Emulatorでは動くのに実機で動かず非常に苦労しました。。Android開発者は各端末の知識も必要で大変ですね;

KotlinでAndroidアラームアプリを作った

Androidのアラームアプリを作ったときにやったこと、調べたことを紹介します。

作ったアプリ

ポップアップアラームという設定した時刻にポップアップを表示するアプリを作りました。
ストアに公開したので、ぜひ触ってみてください!

やったこと

Cordova/PhoneGapでAndroidアプリを作ったことはありますが、ネイティブで作るのは初めてなので、まずは言語仕様の理解から始めました。

  1. Kotlinの理解
  2. 開発環境の構築
  3. 実装
  4. アイコンの作成
  5. リリース

Kotlinの理解

開発言語として、JavaではなくKotlinを選びました。
型推論が欲しいこと、Null安全に興味があったこと、周囲の評判が良かったことが理由です。
※先日、KotlinがAndroidアプリ公式の開発言語に選ばれましたが、僕が選んだ後の話だったのでニュースを見たときは幸せを感じました笑
言語仕様は、その言語を書き始める前にざっと知っておいた方が効率がいいと思っているので、以下の本を読みました。

Kotlinスタートブック

その他、実装中にリスト操作について知りたいことが多かったので、以下の記事を参考にさせていただきました。

Qiita:Kotlin のコレクション使い方メモ

開発環境の構築

Android Studioのインストールは公式サイトより。
Android StudioへのKotlinの導入は、前述のKotlin本を参考にしました。取り急ぎこれで十分かと。
JavaのコードをコピペするとKotlinコードに自動的に変換されるのは、Kotlinの大きなメリットでもありますね。

実装

実装した主な機能は以下の通り。

Androidネイティブの実装は初めてということもあり、だいぶ詰まりました…
細かい部分も含めて、別ページで紹介しようと思います。

広告の実装

アプリにバナー広告を実装してみました。使ったのはGoogleのAdMobです。手順は公式サイトを参考のこと。Android Studioと連携できるのでほぼ自動で実装できました。

アイコンの作成

アイコンの作成には、Inkscapeという無料の画像編集ソフトを使いました。

リリース

リリースの際、APKに署名する必要がありますが、これもAndroid Studioからできます。
むしろ、アプリの説明文を記載するのがなかなか大変ですね。

かかった時間

ざっくりですが、開発にかかった実時間の内訳は以下のような感じ。
といっても期間としては3ヶ月ぐらいかかってます。途中、実装に詰まって手が止まりました;

  • Kotlinの理解 → 1日
  • 開発環境の構築 → 1日
  • 実装 → 2週間
  • アイコンの作成 → 半日
  • リリース → 1日

振り返り

Contextの扱いであったりResourceファイルの違いであったり、Android開発の知識が乏しく実装中に手が止まることが多かったです。実装する前にAndroidの基礎本を読んでおけばよかったかなと。
試しに広告を入れてみましたが、はじめから広告ありきで画面設計、実装しておけば、広告を表示する隙間をあとで開ける必要はなかったかなと。