0

Complete project:

https://github.com/giseletoledo/MonitorSaude/tree/master/app/src/main/java/com/oceantech/monitorsaude

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
          }
      }
  }
} ``` 



gise
  • 13
  • 2
  • 10
  • Could you post the _entire_ error? – Ryan M Apr 27 '23 at 00:02
  • Too long for comment, but now fix the error, with the answer above, thank you. FATAL EXCEPTION: main Process: com.oceantech.monitorsaude, PID: 7434 java.lang.RuntimeException: Cannot create an instance of class com.oceantech.monitorsaude.viewmodel.MedicamentoViewModel – gise Apr 27 '23 at 00:52

1 Answers1

0

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.

Mikhail Guliaev
  • 1,168
  • 1
  • 6
  • 14
  • Thank you very much. I will learn how to use DI with Hilt/Dagger. I found confusing that part of viewModel, I will study more about it. – gise Apr 27 '23 at 00:45
  • ViewModel is not necessary while using DI, it is just the way you organise architecture in your project. You can pick any architecture you want (MVP/MVI for example). But MVVM is most convenient to my mind and moreover is being promoted by Google – Mikhail Guliaev Apr 27 '23 at 07:49
  • Yes, it`s a way to organize. I didn't know about the use of application, because in another app i just install dependencies for navigation and by viewmodel, the use of viewmodelprovider and application wasn't needed to work. – gise Apr 28 '23 at 02:32