ユーザ用ツール

サイト用ツール


サイドバー

プログレス合同会社

広告

android:studio:application:core-data-module

17.データモジュールの作成

データの一元管理を行うためデータモジュール(:core:data)を作成します。

また、データの永続化はRoomで行います。

Roomの導入

バージョンカタログファイルにRoomのバージョン定義を追記します。

[versions]
   :
room = "2.8.2"                      # https://mvnrepository.com/artifact/androidx.room/room-runtime

[libraries]
   :
room-runtime  = { module = "androidx.room:room-runtime",  version.ref = "room" }
room-compiler = { module = "androidx.room:room-compiler", version.ref = "room" }
room-ktx      = { module = "androidx.room:room-ktx",      version.ref = "room" }

3行目[versions]
コメント部分のURLを参照して、最新安定バージョンを指定します。
7行目~9行目[libraries]
Roomライブラリモジュールとバージョンを関連付けします。

追記後、『Sync Now』で内容をプロジェクトに反映させます。

データ管理モジュールの作成

データを管理するモジュール(:core:data)を作成します。

uiモジュールの作成と同様に、トップディレクトリで:core:dataを作成し、javaディレクトリ名の変更を行います。

LibraryConfigurePluginの適用

:core:dataモジュールのbuild.gradle.ktsLibraryConfigurePluginを適用します。

plugins {
  alias(libs.plugins.android.library)
  alias(libs.plugins.kotlin.android)
  id("build.logic.library.configure")
}

android {
  namespace = "jp.co.progress_llc.portal.core.data"
  compileSdk {
    version = release(36)
  }

  defaultConfig {
    minSdk = 28

    testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
    consumerProguardFiles("consumer-rules.pro")
  }

  buildTypes {
    release {
      isMinifyEnabled = false
      proguardFiles(
        getDefaultProguardFile("proguard-android-optimize.txt"),
        "proguard-rules.pro"
      )
    }
  }
  compileOptions {
    sourceCompatibility = JavaVersion.VERSION_11
    targetCompatibility = JavaVersion.VERSION_11
  }
  kotlinOptions {
    jvmTarget = "11"
  }
}

dependencies {

  implementation(libs.androidx.core.ktx)
  implementation(libs.androidx.appcompat)
  implementation(libs.material)
  testImplementation(libs.junit)
  androidTestImplementation(libs.androidx.junit)
  androidTestImplementation(libs.androidx.espresso.core)
  implementation(libs.room.runtime)
  implementation(libs.room.ktx)
  ksp(libs.room.compiler)
  implementation(libs.hilt.android)
  ksp(libs.hilt.compiler)

2行目~3行目、9行目~15行目、17行目~35行目、40行目~42行目
ビルドプラグインで定義しているので削除します。
3行目
/build-logic/build.gradle.ktsで定義したビルドプラグインのidを指定します。
16行目、43行目~45行目
テストを行うときまで削除します。
46行目~47行目
Roomの依存関係を追加します。
49行目~50行目
Hiltの依存関係を追加します。

適用後、『Sync Now』で内容をプロジェクトに反映させます。

エンティティの作成

エンティティ(テーブル)定義クラスを作成します。

経路データRoute.ktを作成します。

package jp.co.progress_llc.portal.core.data

import androidx.room.Entity
import androidx.room.PrimaryKey
import androidx.room.ColumnInfo

@Entity(tableName = "route")
data class Route(
  @PrimaryKey(autoGenerate = true)
  val id: Int = 0,
  @ColumnInfo(name = "order_index")
  val orderIndex: Int = 0,                        // 路線の並び順
  @ColumnInfo(name = "from_station")
  val fromStation: String = "",                   // 発駅コード
  @ColumnInfo(name = "to_station")
  val toStation: String = "",                     // 着駅コード
  @ColumnInfo(name = "via_station")
  val viaStation: String = ""                     // 経由駅コード
)

7行目
データベース上のテーブル名をrouteにしています。
9行目
idを主キーにしています。
自動採番します。
10行目、12行目、14行目、16行目
アプリケーションでのカラム名と属性を定義しています。
11行目、13行目、15行目、17行目
データベース上のカラム名を定義しています。

DAOの作成

データベースにアクセスするためのインターフェースオブジェクト(Data Access Object)を作成します。

package jp.co.progress_llc.portal.core.data

import androidx.room.Dao
import androidx.room.Query
import androidx.room.Insert
import androidx.room.OnConflictStrategy

@Dao
interface RouteDao {
  @Query("SELECT * FROM route ORDER BY order_index")
  suspend fun getAllRoute(): List<Route>

  @Insert(onConflict = OnConflictStrategy.REPLACE)
  suspend fun insertRoute(route: Route): Long
}

10行目~11行目
レコードを全件取得します。
13行目~14行目
レコードを追加します。
主キーのレコードが既に存在する場合は置換します。

リポジトリの作成

アプリケーションのビジネスロジックで直接DAOを触らせると、将来データベースをRoom以外にしたとき(例えばJOSNファイル)にビジネスロジックを修正する必要があります。

ビジネスロジック側からデータソースを意識させないようにするため、リポジトリを作成してDAOを隠蔽します。
※今回のアプリケーション規模では冗長です。

RouteDao用に、repositoryディレクトリ(新規に作成)内にリポジトリインターフェースRouteRepository.ktを作成します。

package jp.co.progress_llc.portal.core.data.repository

import jp.co.progress_llc.portal.core.data.Route

/**
 * Routeのリポジトリインターフェース
 */
interface RouteRepository {
  /**
   * Routeを全件取得
   */
  suspend fun getAllRoute(): List<Route>

  /**
   * Routeレコードを追加
   */
  suspend fun insertRoute(route: Route): Long
}

9行目~12行目
レコードを全件取得します。
14行目~17行目
レコードを追加します。

リポジトリインターフェースの実装RouteRepositoryImpl.ktを作成します。

package jp.co.progress_llc.portal.core.data.repository

import javax.inject.Singleton
import javax.inject.Inject
import jp.co.progress_llc.portal.core.data.Route
import jp.co.progress_llc.portal.core.data.RouteDao

/**
 * Routeのリポジトリ実装
 */
@Singleton
class RouteRepositoryImpl @Inject constructor(
  private val routeDao: RouteDao
) : RouteRepository {
  override suspend fun getAllRoute(): List<Route> {
    return routeDao.getAllRoute()
  }

  override suspend fun insertRoute(route: Route): Long {
    return routeDao.insertRoute(route)
  }
}

11行目~12行目
DI(Hilt)の注入対象にしています。
15行目~17行目
レコードを全件取得します。
19行目~20行目
レコードを追加します。

データベースの作成

:core:dataAppDatabaseクラスを作成します。

package jp.co.progress_llc.portal.core.data

import androidx.room.Database
import androidx.room.Room
import androidx.room.RoomDatabase
import android.content.Context

@Database(
  entities = [Route::class],
  version = 1,
  exportSchema = false
)

abstract class AppDatabase : RoomDatabase() {
  abstract fun RouteDao(): RouteDao

  companion object {
    @Volatile
    private var INSTANCE: AppDatabase? = null

    fun getDatabase(context: Context): AppDatabase {
      return INSTANCE ?: synchronized(this) {
        val instance = Room.databaseBuilder(
          context.applicationContext,
          AppDatabase::class.java,
          "app_database"
        )
          .build()
        INSTANCE = instance
        instance
      }
    }
  }
}

8行目~12行目
データベース全体の構造を定義しています。
14行目~34行目
データベースのインスタンスを作成しています。
26行目
データベースの名前を定義しています。
30行目
データベースのインスタンスを戻り値にしています。

DI(Hilt)モジュールの作成

RoomDatabaseDAO、およびリポジトリをDI(Hilt)で注入可能にするため、DI(Hilt)モジュールを作成します。

DI(Hilt)モジュールは、diディレクトリ内に作成します。

package jp.co.progress_llc.portal.core.data.di

import javax.inject.Singleton
import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import jp.co.progress_llc.portal.core.data.AppDatabase
import jp.co.progress_llc.portal.core.data.RouteDao
import jp.co.progress_llc.portal.core.data.repository.RouteRepository
import jp.co.progress_llc.portal.core.data.repository.RouteRepositoryImpl

@Module
@InstallIn(SingletonComponent::class)
object DataModule {

  @Provides
  @Singleton
  fun provideAppDatabase(@ApplicationContext context: Context): AppDatabase {
    return AppDatabase.getDatabase(context)
  }

  @Provides
  fun provideRouteDao(database: AppDatabase): RouteDao {
    return database.RouteDao()
  }

  @Provides
  @Singleton
  fun provideRouteRepository(
    routeDao: RouteDao
  ): RouteRepository {
    return RouteRepositoryImpl(routeDao)
  }
}

15行目~16行目
DI(Hilt)モジュールであることを定義しています。
19行目、25行目、30行目
戻り値がDI(Hilt)の依存オブジェクトであることを定義しています。
21行目~23行目
依存オブジェクトとして、AppDatabaseを定義しています。
26行目~28行目
依存オブジェクトとして、RouteDaoを定義しています。
32行目~36行目
依存オブジェクトとして、RouteRepositoryを定義しています。

android/studio/application/core-data-module.txt · 最終更新: by 管理者