Home > Software design >  how to delete room database when app closed?
how to delete room database when app closed?

Time:10-02

i tried to call ViewModel to delete table when activity Destroy but it not work, when i call ViewModel when activity stop i get a error.

DAO interface

@Dao
interface NoteDAO {

    @Query("select * from note_table")
    fun getAllNote() : LiveData<List<Note>>

        @Query("DELETE FROM note_table")
        fun deleteAllData()
}

Repository

class NoteRepository(app:Application) {
    private val noteDAO : NoteDAO
    init {
        val noteDatabase: NoteDatabase = NoteDatabase.getInstance(app)
        noteDAO = noteDatabase.getNoteDao()
    }

    fun getAllNote():LiveData<List<Note>> = noteDAO.getAllNote()

    fun deleteAllData() = noteDAO.deleteAllData()
}

Viewmodel

class NoteViewModel(app: Application): ViewModel() {
    private val noteRepository: NoteRepository = NoteRepository(app)
    
    fun deleteAllData() = noteRepository.deleteAllData()

    fun getAllNote() : LiveData<List<Note>> = noteRepository.getAllNote()

    class NoteViewModelFactory(private val application: Application) : ViewModelProvider.Factory{
        override fun <T : ViewModel?> create(modelClass: Class<T>): T {
            if(modelClass.isAssignableFrom(NoteViewModel::class.java)){
                return NoteViewModel(application) as T
            }
            throw IllegalArgumentException("Unable construct viewmodel")
        }
    }
}

when i call in onStop method

 override fun onStop() {
        super.onStop()
        noteViewModel.deleteAllData()
    }

i get the error

 java.lang.RuntimeException: Unable to stop activity {com.example.database/com.example.database.MainActivity}: java.lang.IllegalStateException: Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
        at android.app.ActivityThread.callActivityOnStop(ActivityThread.java:4624)
        at android.app.ActivityThread.performStopActivityInner(ActivityThread.java:4594)
        at android.app.ActivityThread.handleStopActivity(ActivityThread.java:4669)
        at android.app.servertransaction.StopActivityItem.execute(StopActivityItem.java:41)
        at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)
        at android.os.Handler.dispatchMessage(Handler.java:107)
        at android.os.Looper.loop(Looper.java:214)
        at android.app.ActivityThread.main(ActivityThread.java:7356)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

please help me and have a nice day,everyone!

CodePudding user response:

You are running a database query on Main Thread which could potentially block UI. You should use coroutines to execute your queries on the background thread.

Make your deleteAllData method suspend

@Query("DELETE FROM note_table")
suspend fun deleteAllData()

Also, make deleteAllData method suspend in NoteRespository

suspend fun deleteAllData() = noteDAO.deleteAllData()

In your NoteViewModel class, call this method in viewModelScope

fun deleteAllData() = viewModelScope.launch {
        noteRepository.deleteAllData()
    }

CodePudding user response:

if you want to perform database operation on main thread then add this line while building database object

.allowMainThreadQueries()

Full Sample

Room.databaseBuilder(appContext,LocalDatabase::class.java,"app.db")
     .fallbackToDestructiveMigration()
     .allowMainThreadQueries()
     .build()

But It's not good practice to perform a database operation on the main thread. You must use coroutines to perform database operation

CodePudding user response:

you can use couroutine

 override fun onStop() {
    super.onStop()
    GlobalScope.launch{
       noteViewModel.deleteAllData()
    }
}

or you can write it in your view model like it

 fun deleteAllData() = viewModelScope.launch {
        noteRepository.deleteAllData()
    }

CodePudding user response:

I would do it in the onStop lifecycle function, calling the viewmodel, and in the viewmodel calling a coroutine executed in a background thread.

Activity/Fragment:

 override fun onStop() {
      viewModel.wipeData()
}

ViewModel:

class ViewModel @Inject constructor (wipeDataUseCase: WipeDataUseCase){
    fun wipeData() {
    
       viewModelScope.launch(IO) {
           when (wipeDataUseCase()){
               true -> {
                  //do something
               }
               false -> {
                  // do something
               }

           }
       }
    }
}

Use Case:

class WipeDataUseCase @Inject constructor (roomDataBase: RoomDataBase){
  suspend operator fun invoke() = roomDataBase.dao().wipeData()
}

I would've use the coroutine mentioned above, launching the process in the background calling its respective Use Case.

As it is meant to be on the moment that the app is over there is no much thing to play with the callback of the wiping data operation.

  • Related