0
votes

Base de données sur la chambre: Obtenir Sélectionnez Max () deux fois après la création d'un nouvel article RecyclerVoir

J'ai une liste de recyclerview d'éléments de carte de carte qui fonctionne correctement. Lors de la création d'une nouvelle carte qui est insérée dans la base de données, je voudrais déclencher un toast qui informe l'utilisateur que la View a été ajoutée avec succès et afficher le numéro de CardView. Le numéro de CardView est l'ID de l'élément CardView inséré dans la base de données. Les données sont enregistrées dans la base de données lorsque l'utilisateur clique sur un bouton d'enregistrement qui déclenche OnClickSave ().

I Configurez une @query dans le DAO pour obtenir le max (cardid): P>

public class SQLiteDB extends SQLiteOpenHelper {

    ...
    public int getLastInsertId() {

    int index = 0;
    SQLiteDatabase sdb = getReadableDatabase();
    Cursor cursor = sdb.query(
            "sqlite_sequence",
            new String[]{"seq"},
            "name = ?",
            new String[]{TABLE_NAME},
            null,
            null,
            null,
            null
    );

    sdb.beginTransaction();
    try {
        if (cursor !=null) { 
            if (cursor.moveToLast()) {                    
                index = cursor.getInt(cursor.getColumnIndex("seq"));
            }
        }
    ...
    }         
    return index;
}      


14 commentaires

Il n'y a pas `mviewmodel.insercard (carte1); `Méthode dans ViewModel . Partagez cette partie du code.


@Gensagames fera, par 18h et USA.


@Gensagames ViewModel Insert Card () a été mis à jour. Et le même pour le référentiel et le DAO.


Pouvez-vous déplacer le pain grillé à l'intérieur ViewModel.get max (). Observez () ? Votre toast pourrait-on tirer avant que les données ont été enregistrées et newMax la valeur est mise à jour. @Ajw


@Prokash Sarkar Je comprends votre point mais je ne sais pas comment déplacer le toast à l'intérieur. Pouvez vous donner un exemple?


@Ajw comme ça? mviewmodel.getmax (). Observez (ceci, valeur -> {newmax = valeur; toast.maketext (addorupdatexardactivity.Cette, "carte #" + newmax + "a été enregistré dans la liste", toast.longueur_long). ();}); cela garantit que le toast sera tiré lorsqu'un changement de données s'est produit dans la chambre.


@Prokash Sarkar ah, je vois. De cette façon Newmax est mis à jour et le toast est tiré après, oui?


@Ajw exactement! Faites-moi savoir si cela fonctionne.


@Prokash Sarkar ok donc j'ai déplacé "Msviewmodel.getmax ()." Code de l'ONCREATE () et le mettre juste en dessous "MVVueModel.insercard (Card1)". Le toast a tiré mais il a tiré deux fois. Tout d'abord, il a tiré et dit que la carte précédente était simplement enregistrée. Ensuite, il a tiré à nouveau et dit que la dernière carte # était juste sauvée. Ainsi, faire des progrès, car le deuxième toast ajusté correctement et montré le numéro de carte correct enregistré pour la dernière carte qui a été insérée dans la base de données. Mais le premier toast ne devrait pas tirer le feu car cette vision était précédemment enregistrée.


@Prokash Sarkar J'utilise également getmax () dans une autre activité pour observer le max de la base de données. Il y a peut-être un conflit avec les deux observateurs, c'est pourquoi il tire deux fois. Je vais re-nommer getmax () dans l'addorupdateCardactivity pour voir si cela résout le problème. Faites-moi savoir si vous avez d'autres idées sur la manière de résoudre.


@Ajw vous avez utilisé différentes dao instance pour insérer et observer. Ils doivent être identiques à toutes les opérations.


Donc, parce qu'il y a deux instances DAO, le toast tire deux fois?


@Prokash Sarkar Comment faire la même instance Dao? Modifiez l'instance DAO dans le référentiel pour observer pour correspondre à l'instance DAO de la tâche ASYNC pour INSERT?


@Ajw j'ai posté ma réponse. Faites-moi savoir si cela fonctionne.


3 Réponses :


0
votes

En raison de l'utilisation de l'asyncaptage pour insérer une carte à la base de données, cette fonction prend un certain temps pour terminer et vous montrer votre toast, instantanément! Changez votre activité à ceci:

AddorUpdateCardActivity
...
private int newMax = -1;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    mViewModel = new ViewModelProvider(this).get(cardViewModel.class);

    mViewModel.getMax().observe(this, integer2 -> {
        newMax = integer2;
        Toast.makeText(AddorUpdateCardActivity.this, "card #" + newMax + " was saved to the list", Toast.LENGTH_LONG).show();
        hideProgressBar();
    });
}

public void onClickSave(View v) {

    //set card data
    // then insert data in database
    mViewModel.insertCard(card1);

    showProgressBar();
}


2 commentaires

Je voudrais que le toast soit tiré après que l'utilisateur clique sur Insère les nouvelles données de View dans la base de données. Donc, je ne devrais pas devoir déplacer le code d'observateur de mviewmodel.getmax () ... sur Oncreate () et le mettre juste après Mviewmodel.insercard () dans l'Onclicksave ()? Sinon, comment le toast est-il déclenché s'il est assis sur Oncreate ()?


De plus, l'application se bloque lorsque la liste est vide et que j'essaie d'ajouter la première carte à l'aide de AddorupDatCardActivity. Le logcat dit que l'entier est Null Object Référence.



1
votes

La salle Insérer code> Fonctionnement à l'intérieur AsynccTask code> prend un certain temps avant que la variable maxcount code> est mise à jour. Puisque vous montrez le toast code> à l'intérieur d'un bouton Cliquez, le message est affiché immédiatement sans recevoir la valeur mise à jour de LivetaA code>.

Déplacez le message code> Toast code> à l'intérieur de la méthode Obverve () CODE> de sorte qu'il ne soit déclenché qu'après un LivetaA code> Changement. P> XXX PRE>

À ce stade, le code doit fonctionner, mais vous obtiendrez plusieurs événements LiveTata ​​code> pour un seul Insérer code>. Cela se passe parce que vous avez utilisé 2 instances distinctes de dao fort> pour insert code> et requête code> opération. P>

public cardRepository(Application application) {
        RoomDatabase db = RoomDatabase.getDatabase(application);
        cardDao = db.cardDao();
    }

    public LiveData<Integer> getMax() {
        return cardDao.getMax();  
    }

     public void insertCard(Card newcard) {
        AsyncTask.execute(() -> cardDao.insertCard(newcard));
    }


2 commentaires

Ah, ok donnera à votre solution un essai. Je devrais avoir la même instance Dao pour toutes les opérations de crud, corriger? Donc Supprimer () et UpdateCard () devraient également utiliser «CardDao ...», pas leur propre instance DAO unique?


Le toast a tiré, mais il a tiré deux fois à nouveau, même après avoir effectué une instance DAO pour insertion () et GetMax (). Voir le code révisé ci-dessus en fonction de votre réponse. D'abord, le toast a tiré et a déclaré que la carte précédente a été sauvée. Ensuite, il a tiré à nouveau et a dit que la dernière carte # a été sauvée. Donc, le deuxième toast ajusté correctement et montré le numéro de carte correct enregistré pour la dernière carte qui a été insérée dans la base de données. Mais le premier toast ne devrait pas tirer le feu car cette vision était précédemment enregistrée. Des idées pour résoudre le problème?



1
votes

Les opérations de modèle d'affichage que vous appelez dans onclicksave sont asynchrones: xxx

La mise en œuvre de LivetaA enregistre la version de données ainsi que la dernière version vue par l'observateur.

par conséquent insertcard commence à fonctionner sur un thread de travailleur pendant que vous commencez à observer getmax du fil principal avec une nouvelle Observateur créé. Ainsi, vous recevrez la valeur actuelle ainsi que la nouvelle valeur après la mise à jour de la base de données.

à la place, vous ne pouvez l'observer qu'une fois dans Oncreate () et attendez les mises à jour déclenché par la base de données: xxx


6 commentaires

Ah ok. Alors, comment puis-je limiter le toast pour ne être déclenché que par la méthode d'insertion (lorsqu'une carte de carte est ajoutée à la base de données) de sorte qu'elle ne se déclenche pas lorsque d'autres opérations de crud se produisent comme une méthode de suppression ou de mise à jour?


J'ai capturé le max existant dans la base de données, puis la comparé au maximum après la carte intégrée () pour déterminer qu'une nouvelle carte a été ajoutée. Réponse acceptée, upéted et Bounty attribuée. Santé à toi.


Question de suivi: Si je place l'observateur GetMax () dans l'Oncreate (), comment puis-je déterminer que la mise à jour a été déclenchée par la base de données? Je peux donc m'assurer que j'ouvre la dernière version non la version de données.


Je ne pense pas que getmax doit être utilisé pour déterminer l'exactitude de insertcard . Vous devriez faire confiance à salle pour toujours renvoyer l'état correct de la base de données. Vous devez utiliser le résultat de l'appel d'insertion de la base de données pour vérifier si l'insertion a réussi.


OK, alors comment puis-je vous assurer que le code de vérification de l'insertion a été réussi à courir juste après l'insertion? Un clic bouton sur la touche "Enregistrer" exécute le code d'insertion. Juste après l'insertion, j'essaie de configurer des points de courant sur la carte pour des alarmes d'incendie ultérieures pour les notifications. J'essaie d'obtenir des données à partir de la carte nouvellement insérée (par exemple, carte.getid ()) pour configurer les dentifensants, mais je ne sais pas comment obtenir ces données dans le même bloc de code de "OnClickSave". J'apprécierais des idées ou des idées sur la manière de corriger.


Je suggérerais de poser une autre question. C'est trop d'informations pour répondre à un petit commentaire. N'hésitez pas à laisser un lien vers la nouvelle question ici.