メモ > 技術 > IDE: AndroidStudio > アプリの作成(Jetpack Compose / データの保存)
アプリの作成(Jetpack Compose / データの保存)
※今は「SharedPreferences」ではなく「DataStore」を使うことが推奨されているらしいが未検中。
アプリ アーキテクチャ: データレイヤー - DataStore - デベロッパー向け Android | Android デベロッパー | Android Developers
https://developer.android.com/topic/libraries/architecture/datastore?hl=ja
DataStoreを試してみる
https://zenn.dev/slowhand/articles/455aa5cd244e90
【Kotlin/Android Studio】DataStoreの使い方!データの保存と取得方法
https://tech.amefure.com/android-datastore
build.gradle の dependencies 内に以下を追加する
implementation("androidx.datastore:datastore-preferences:1.1.1")
追加したら「Sync Now」をクリックする。
プログラムを記述するファイルの最上位で以下を呼び出すことにより、シングルトンで dataStore にアクセスできるようになる。
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
なお、上記のコードでインポートすべきライブラリは以下のとおり。
import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore
特にPreferencesのインポート時、他の物をインポートしてしまうと、以下のエラーになるので注意。
Property delegate must have a 'getValue(Context, KProperty<*>)' method. None of the following functions is suitable:
public abstract operator fun getValue(thisRef: Context, property: KProperty<*>): DataStore<Preferences> defined in kotlin.properties.ReadOnlyProperty
flow.firstのインポート時も、インポートすべきライブラリは以下なので注意。
import kotlinx.coroutines.flow.first
以下のとおり実装する。
package com.example.helloworld
import android.content.Context
import android.os.Bundle
import android.util.Log
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.activity.enableEdgeToEdge
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material3.Button
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.input.TextFieldValue
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.stringPreferencesKey
import androidx.datastore.preferences.preferencesDataStore
import net.refirio.helloworld.ui.theme.HelloWorldTheme
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import java.io.IOException
val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "settings")
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enableEdgeToEdge()
setContent {
HelloWorldTheme {
Scaffold(modifier = Modifier.fillMaxSize()) { innerPadding ->
MainScreen(modifier = Modifier.padding(innerPadding))
}
}
}
}
}
@Composable
fun MainScreen(modifier: Modifier = Modifier) {
val context = LocalContext.current
var inputText by remember { mutableStateOf(TextFieldValue("")) }
Column(modifier = modifier.padding(16.dp)) {
OutlinedTextField(
value = inputText,
onValueChange = {
inputText = it
},
modifier = Modifier.fillMaxWidth()
)
Spacer(modifier = Modifier.height(16.dp))
Row {
Button(onClick = {
runBlocking(Dispatchers.IO) {
putText(context, inputText.text)
}
}) {
Text("保存")
}
Spacer(modifier = Modifier.width(16.dp))
Button(onClick = {
runBlocking(Dispatchers.IO) {
inputText = TextFieldValue(getText(context))
}
}) {
Text("復元")
}
}
}
}
suspend fun putText(context: Context, text: String) {
try {
context.dataStore.edit { settings ->
settings[stringPreferencesKey("text")] = text
}
} catch (e: IOException) {
Log.d("putText", text)
}
}
suspend fun getText(context: Context): String {
var text = ""
try {
text = context.dataStore.data.first()[stringPreferencesKey("text")].toString()
} catch (e: IOException) {
Log.d("getText", text)
}
return text
}
@Preview(showSystemUi = true)
@Composable
fun MainScreenPreview() {
MainScreen()
}