Complete project:
Hi, I tried many solutions, the first was the official documentation developer android, but didn't work, I don't know if the problem it's because I have one repository with datasource been passed as args, my structure and dependencies. I even create an Application because the code of the docs need Application and don't explain how to generate or if exists:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<application
android:name=".MyApplication"
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MonitorSaude"
tools:targetApi="31">
<activity
android:name=".MedicamentoActivity"
android:theme="@style/Theme.MonitorSaude.NoActionBar"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
</application>
</manifest>
//Application
import android.app.Application;
import org.jetbrains.annotations.NotNull;
public class MyApplication extends Application {
@NotNull
public final MedicamentoRepository medicamentoRepository;
public MyApplication(@NotNull MedicamentoRepository medicamentoRepository) {
this.medicamentoRepository = medicamentoRepository;
}
}
dependencies {
def room_version = '2.5.1'
implementation "androidx.room:room-runtime:$room_version"
kapt "androidx.room:room-compiler:$room_version"
//Lifecycle components
implementation 'androidx.activity:activity-ktx:1.7.1'
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.6.1'
implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1'
implementation 'androidx.lifecycle:lifecycle-common-java8:2.6.1'
implementation 'androidx.fragment:fragment-ktx:1.5.7'
implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0'
implementation 'androidx.core:core-ktx:1.10.0'
implementation 'androidx.navigation:navigation-fragment-ktx:2.5.3'
implementation 'androidx.navigation:navigation-ui-ktx:2.5.3'
// Kotlin Extensions and Coroutines support for Room
implementation "androidx.room:room-ktx:$room_version"
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.core:core-ktx:1.10.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}
class MedicamentoRepository(private val dataSource: MedicamentoDataSource) {
//DataSource
class MedicamentoDataSource(private val medicationDao: MedicamentoDao) {
//ViewModel
class MedicamentoViewModel(private val medicamentoRepository: MedicamentoRepository, private val savedStateHandle: SavedStateHandle) : ViewModel() {
private val _medicamentos = MutableLiveData<List<Medicamento>>()
val medicamentos: LiveData<List<Medicamento>> = _medicamentos
private val _datasSelecionadas = MutableLiveData<List<String>>()
val datasSelecionadas: LiveData<List<String>> = _datasSelecionadas
private val _horariosSelecionados = MutableLiveData<List<String>>()
val horariosSelecionados: LiveData<List<String>> = _horariosSelecionados
fun resetMedicamento() {
// Resete todas as propriedades para o valor inicial
_medicamentos.value = emptyList()
// Chame o método para limpar as listas de datas e horários
limparListas()
}
fun inserirMedicamento(medicamento: Medicamento) {
viewModelScope.launch {
medicamentoRepository.insert(medicamento.copy(datas = datasSelecionadas.value ?: emptyList(), horarios = horariosSelecionados.value ?: emptyList()))
}
limparListas()
}
// Limpa as listas de datas e horários
private fun limparListas() {
_datasSelecionadas.value = emptyList()
_horariosSelecionados.value = emptyList()
}
fun onHorarioSelecionado(timePicker: String) {
val horario = "${timePicker}"
addHorario(horario)
}
fun onDataSelecionada(date: Date) {
val dataFormatada = SimpleDateFormat("dd/MM/yyyy", Locale.getDefault()).format(date)
addData(dataFormatada)
}
fun loadMedications() {
viewModelScope.launch {
_medicamentos.value = medicamentoRepository.getAll()
}
}
private fun addData(data: String) {
_datasSelecionadas.value = (_datasSelecionadas.value ?: emptyList()) + listOf(data)
}
private fun addHorario(horario: String) {
_horariosSelecionados.value = (_horariosSelecionados.value ?: emptyList()) + listOf(horario)
}
suspend fun getById(id: Int): Medicamento? = medicamentoRepository.getById(id)
fun deleteMedication(medicamento: Medicamento) {
viewModelScope.launch {
medicamentoRepository.delete(medicamento)
}
}
// Define ViewModel factory in a companion object
companion object {
val Factory: ViewModelProvider.Factory = object : ViewModelProvider.Factory {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(
modelClass: Class<T>,
extras: CreationExtras
): T {
// Get the Application object from extras
val application = checkNotNull(extras[APPLICATION_KEY])
// Create a SavedStateHandle for this ViewModel from extras
val savedStateHandle = extras.createSavedStateHandle()
return MedicamentoViewModel(
(application as MyApplication).medicamentoRepository,
savedStateHandle
) as T
}
}
}
} ```
You have incorrectly declared the MyApplication
class. As a component of the Android SDK, the application is automatically created by Android. Therefore, you cannot define custom constructors here, as Android only recognizes the default constructor without arguments.
To initialize properties, you should use the onCreate()
callback method, which is called by the Android system when creating your Application class.
You can use this part of code to define MyApplication
class.
package com.oceantech.monitorsaude;
import android.app.Application;
import com.oceantech.monitorsaude.database.AppDatabase;
import com.oceantech.monitorsaude.database.dao.MedicamentoDao;
public class MyApplication extends Application {
private MedicamentoDao medicamentoDao;
private MedicamentoDataSource medicamentoDataSource;
public MedicamentoRepository medicamentoRepository;
@Override
public void onCreate() {
super.onCreate();
this.medicamentoDao = AppDatabase.Companion.getInstance(this).medicamentoDao();
this.medicamentoDataSource = new MedicamentoDataSource(medicamentoDao);
this.medicamentoRepository = new MedicamentoRepository(medicamentoDataSource);
}
}
Also I would like to recommend you to consider DI (Dependency Injection) frameworks to not create dependencies inside the application class, and provide it from outside instead. You can check Dagger/Hilt for example. This will make your code more suitable for tests and more maintainable.