2
votes

Comment puis-je supprimer un LiveData en utilisant Room et LiveData dans une activité?

Je crée une application Android en utilisant Kotlin et les composants d'architecture Android (LiveData et Room).

J'ai une activité où j'affiche un utilisateur (qui est stocké dans une base de données et récupéré à l'aide d'une requête avec un ViewModel).

Je dois avoir les options pour modifier ou supprimer l'utilisateur actuel. Le problème est que lorsque j'essaie de supprimer l'utilisateur, l'application se bloque, mais lorsque je l'ouvre à nouveau, les utilisateurs sont partis.

Voici mon code de classe complet:

    2019-01-10 22:29:09.573 2984-3066/? E/WindowManager: win=Window{6686c65 u0 com.kps.spart.moskimedicationreminder/com.kps.spart.moskimedicationreminder.MainActivity EXITING} destroySurfaces: appStopped=false win.mWindowRemovalAllowed=false win.mRemoveOnExit=false win.mViewVisibility=8, caller=com.android.server.wm.AppWindowToken.destroySurfaces:748 com.android.server.wm.AppWindowToken.destroySurfaces:732 com.android.server.wm.WindowState.onExitAnimationDone:5523 com.android.server.wm.AppWindowAnimator.stepAnimationLocked:517 com.android.server.wm.AppWindowToken.stepAppWindowsAnimation:1745 
2019-01-10 22:29:12.443 1269-1269/com.kps.spart.moskimedicationreminder E/ViewRootImpl: sendUserActionEvent() returned.
2019-01-10 22:29:12.465 2984-3066/? E/WindowManager: win=Window{667c3c2 u0 com.kps.spart.moskimedicationreminder/com.kps.spart.moskimedicationreminder.DetallesPerfilActivity EXITING} destroySurfaces: appStopped=false win.mWindowRemovalAllowed=true win.mRemoveOnExit=true win.mViewVisibility=0, caller=com.android.server.wm.AppWindowToken.destroySurfaces:748 com.android.server.wm.AppWindowToken.destroySurfaces:732 com.android.server.wm.WindowState.onExitAnimationDone:5523 com.android.server.wm.WindowStateAnimator.stepAnimationLocked:553 com.android.server.wm.DisplayContent.lambda$-com_android_server_wm_DisplayContent_21292:465 
2019-01-10 22:29:13.591 1269-1269/com.kps.spart.moskimedicationreminder E/ViewRootImpl: sendUserActionEvent() returned.
2019-01-10 22:29:13.634 1269-1269/com.kps.spart.moskimedicationreminder E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.kps.spart.moskimedicationreminder, PID: 1269
    kotlin.KotlinNullPointerException
        at com.kps.spart.moskimedicationreminder.DetallesPerfilActivity$onCreate$1.onChanged(DetallesPerfilActivity.kt:43)
        at com.kps.spart.moskimedicationreminder.DetallesPerfilActivity$onCreate$1.onChanged(DetallesPerfilActivity.kt:23)
        at android.arch.lifecycle.LiveData.considerNotify(LiveData.java:109)
        at android.arch.lifecycle.LiveData.dispatchingValue(LiveData.java:126)
        at android.arch.lifecycle.LiveData.setValue(LiveData.java:282)
        at android.arch.lifecycle.LiveData$1.run(LiveData.java:87)
        at android.os.Handler.handleCallback(Handler.java:790)
        at android.os.Handler.dispatchMessage(Handler.java:99)
        at android.os.Looper.loop(Looper.java:164)
        at android.app.ActivityThread.main(ActivityThread.java:7000)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:441)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1408)
2019-01-10 22:29:13.732 1958-1958/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2019-01-10 22:29:14.519 4660-4799/? E/PBSessionCacheImpl: sessionId[20496443867522706] not persisted.
2019-01-10 22:29:15.547 2984-3636/? E/Watchdog: !@Sync 1101 [2019-01-10 22:29:15.547]
2019-01-10 22:29:34.739 2027-2027/? E/FeatureClassSet: [#CMH#] Rubin package not supported 
2019-01-10 22:29:43.943 6319-6637/? E/BtGatt.GattService: [GSIM LOG]: gsimLogHandler, msg: MESSAGE_SCAN_START, appName: com.google.uid.shared, scannerId: 4, reportDelayMillis=0
2019-01-10 22:29:44.619 2052-2052/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2019-01-10 22:29:45.540 3655-3695/? E/RequestManager_FLP: [LocationManagerService] Location remove 552b5a4 from system
2019-01-10 22:29:45.554 2984-3636/? E/Watchdog: !@Sync 1102 [2019-01-10 22:29:45.554]
2019-01-10 22:29:45.896 6319-6637/? E/BtGatt.GattService: [GSIM LOG]: gsimLogHandler, msg: MESSAGE_SCAN_STOP, appName: com.google.uid.shared, scannerId: 4, reportDelayMillis=0
2019-01-10 22:29:54.628 2081-2081/? E/Zygote: isWhitelistProcess - Process is Whitelisted
2019-01-10 22:29:54.963 2081-2081/? E/zygote: The String#value field is not present on Android versions >= 6.0
2019-01-10 22:29:55.147 2081-2081/? E/TTS: Unparsable line in file with voice data checksums: voices-list.dev/signature.sf 7846532c8eb3d4d374813dae6d74638b
2019-01-10 22:29:55.147 2081-2081/? E/TTS: Unparsable line in file with voice data checksums: voices-list.dev/voices-list-dsig.pb c1024b1416240bb24b316bac696f5cdb
2019-01-10 22:29:55.148 2081-2081/? E/TTS: Unparsable line in file with voice data checksums: voices-list.rel/signature.sf 93ee1641133be6e6d8cb83934833cd8c
2019-01-10 22:29:55.148 2081-2081/? E/TTS: Unparsable line in file with voice data checksums: voices-list.rel/voices-list-rsig.pb 8ad16260ab46941c146c4598d78862ee
2019-01-10 22:29:55.574 2081-2107/? E/native: compressed_store.h:386 Read: Failed to read compressed states.
2019-01-10 22:30:13.464 3531-3531/? E/KeyguardFingerPrint: updateFingerprintListeningState#mFingerprintRunningState=0 shouldListenForFingerprint=true
2019-01-10 22:30:13.464 3531-3531/? E/KeyguardFingerPrint: startListeningForFingerprint()

}

Et l'erreur que j'ai obtenue est celle-ci dans le logcat:

class DetallesPerfilActivity : AppCompatActivity() {

private var user_id : Int = -1
lateinit var usuarioViewModel: UsuarioViewModel
private lateinit var usuarioActual : Usuario

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_detalles_perfil)

    toolbar.title = getString(R.string.detalle_usuario)
    setSupportActionBar(toolbar)
    val ab = supportActionBar
    ab!!.setDisplayHomeAsUpEnabled(true)

    user_id = intent.getIntExtra("USER_ID", -1)

    usuarioViewModel = ViewModelProviders.of(this).get(UsuarioViewModel::class.java)

    usuarioViewModel.getUsuario(user_id).observe(this, Observer {
        usuarioActual = it!!
        populateUserFieldsFromDB()
    })

}

override fun onCreateOptionsMenu(menu: Menu): Boolean {
    menuInflater.inflate(R.menu.menu_edit,menu)
    return true
}

override fun onOptionsItemSelected(item: MenuItem?): Boolean {
    when(item?.itemId){
        android.R.id.home ->{
            onBackPressed()
            return true
        }
        R.id.edit_item ->{
            val builder = AlertDialog.Builder(this@DetallesPerfilActivity)
            builder.setItems(R.array.dialogo_editar_eliminar){
                dialog, which ->
                when(which){
                    0-> {
                        val nav = Intent(this@DetallesPerfilActivity, RegistrarUsuarioActivity::class.java)
                        nav.putExtra("USER_ID", user_id)
                        startActivityForResult(nav,349)
                    }
                    1 -> {
                        val innerBuilder = AlertDialog.Builder(this@DetallesPerfilActivity)
                        innerBuilder.setTitle(getString(R.string.eliminar_usuario))
                                .setMessage(getString(R.string.esta_seguro_que_desea_eliminar_usuario))
                                .setPositiveButton(getString(R.string.si)){
                                    dialog, id ->
                                    deleteUser()
                                }
                                .setNegativeButton(getString(R.string.no)){
                                    dialog, id ->
                                }
                        val innerDialog = innerBuilder.create()
                        innerDialog.show()
                    }
                }
            }
            val dialog = builder.create()
            dialog.show()
            return true
        }
    }
    return super.onOptionsItemSelected(item)
}


private fun populateUserFieldsFromDB(){

        NombreApellidosUsuarioTV.text = "${usuarioActual.nombre} ${usuarioActual.apellidos}"
        GeneroUsuarioTV.text = usuarioActual.genero
        EdadUsuarioTV.text = usuarioActual.edad.toString()

}

private fun deleteUser(){
        usuarioViewModel.delete(usuarioActual)
        Toast.makeText(this@DetallesPerfilActivity,getString(R.string.usuario_eliminado_correctamente),Toast.LENGTH_SHORT).show()
        finish()
}

Alors, comment puis-je supprimer un objet LiveData à l'aide d'un ViewModel sans planter l'application?


8 commentaires

Que voulez-vous dire par BD au fait?


Une base de données SQLite créée avec room et interrogée à l'aide de l'usuario ViewModel.


C'est ce que je demande. Quelle est la forme complète de BD? D signifie très probablement Databse. Mais que signifie B?


J'ai répondu à votre question en passant. Regardez ceci, s'il vous plaît.


Désolé, c'était une faute de frappe (dommage pour moi), c'était DB (DataBase)


@EduardoCorona Answer of ankuranurag2 travaille pour vous ou pas!


Vous obtenez juste une KotlinNullPointerException dans votre Observer: stackoverflow.com/questions/50716294/...


Le supprimez-vous de manière asynchrone? car il plantera si vous le faites sur le fil de l'interface utilisateur


3 Réponses :


1
votes

Une façon simple de le faire est d'ajouter une vérification nulle sur la valeur observée.

 usuarioViewModel.getUsuario(user_id).observe(this, Observer {
    if(it!=null){
        usuarioActual = it
        populateUserFieldsFromDB()
    }
})


0 commentaires

2
votes

Donc, j'ai finalement trouvé la solution à ce problème, L'erreur a été produite lorsque je supprime l'usuario avec usuarioViewModel l'observateur obtient une référence nulle, pour résoudre ce problème, je dois supprimer l'observateur de LiveData et supprimer l'utilisateur après cela.

Je garde d'abord une référence aux LiveData actuels:

private fun deleteUser(){
    if(usuarioActualLive.hasObservers()){
        usuarioActualLive.removeObservers(this@DetallesPerfilActivity)
        usuarioViewModel.delete(usuarioActualLive.value!!)
        finish()
    }
}

Donc, quand je veux supprimer l'utilisateur actuel, je supprime l'observateur anonyme avec:

XXX


1 commentaires

C'est très utile. Je vous remercie



0
votes

J'ai utilisé la liaison de données et la solution d'Eduardo Corona n'a pas fonctionné pour moi. Enfin, j'utilise Transformations pour la conversion pour éviter d'observer b directement

  var note:LiveData<Note> = Transformations.map(_note){it?:Note()}


0 commentaires