Aller au contenu

listview + BD SQLite


thefranchise

Recommended Posts

Bonjour tout le monde.

Je suis débutant en dév' Android, donc si jamais vous voyez des ignominies sans nom dans mon code, ne me jetez pas de pierres ^^'

Voilà, je développe pour les cours une appli de gestion de bibliothèque.

Ce que je veux faire : une page de consultation, qui afficherait dans une listview, les titres des livres enregistrés dans la BD. Puis lors du clic sur un élément, une autre page s'afficherait avec les infos générales du livre (ou un Toast je ne sais pas encore).

J'ai essayé maintes fois de le faire depuis 2 semaines, mais je n'arrive à rien (j'avais toujours des bugs avant).

Aujourd'hui j'ai réussi à faire un truc sans bug, android ne plante pas, MAIS ça ne m'affiche rien -_-

Voici ma fonction qui sélectionne les livres (et qui marche puisque quand j'y fais appel, et que je fais un toast, elle m'affiche bien le premier livre qui est dans ma table)

public Cursor getAllLivre2(){
	return bdd.rawQuery("select _id,titre from table_livres", null);
}

Voici mon appel dans ce qui me sert de test

Cursor c = livreBdd.getAllLivre2();
       startManagingCursor(c);
       SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.liste, c, new String[]{"titre"},new int[]{R.id.titreLivre});

Voici mon fichier liste.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >

   <TextView android:id="@+id/titreLivre"
         android:layout_width="fill_parent"
         android:layout_height="fill_parent"
         android:textSize="16px"
         android:textStyle="bold"
         />
</LinearLayout>

et enfin voici mon fichier main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
   android:orientation="vertical"
   android:layout_width="fill_parent"
   android:layout_height="fill_parent"
   >
  <ListView
       android:id="@+id/listelivre"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
     />
</LinearLayout>

Merci d'avance pour votre aide.

Lien vers le commentaire
Partager sur d’autres sites

Voici mon fichier de test

package projet.bibliotheque;



import android.app.Activity;
import android.database.Cursor;
import android.os.Bundle;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;

public class test extends Activity {
   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

       //Création d'une instance de ma classe LivresBDD
       LivresBDD livreBdd = new LivresBDD(this);

       //Création d'un livre
       Livre livre1 = new Livre("123456789", "Programmez pour Android", "XX XX", "Atlas");
       Livre livre2 = new Livre("111111111", "Android pour les nuls", "XX XX", "Hachette");

       //On ouvre la base de données pour écrire dedans
       livreBdd.open();
       //On insère le livre que l'on vient de créer
       livreBdd.insertLivre(livre1);
       livreBdd.insertLivre(livre2);

       //Pour vérifier que l'on a bien créé notre livre dans la BDD
       //on extrait le livre de la BDD grâce au titre du livre que l'on a créé précédemment
       //Livre livreFromBdd = livreBdd.getLivreWithTitre(livre.getTitre());
       //Livre livreFromBdd = livreBdd.getAllLivre();
       Cursor c = livreBdd.getAllLivre2();
       startManagingCursor(c);
       SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.liste, c, new String[]{"titre"},new int[]{R.id.titreLivre});

       //Si un livre est retourné (donc si le livre à bien été ajouté à la BDD)
      /*if(livreFromBdd != null){
       	//On affiche les infos du livre dans un Toast
       	Toast.makeText(this, livreFromBdd.toString(), Toast.LENGTH_LONG).show();
       	//On modifie le titre du livre
       	/*livreFromBdd.setTitre("J'ai modifié le titre du livre");
       	//Puis on met à jour la BDD
           livreBdd.updateLivre(livreFromBdd.getId(), livreFromBdd);
       }

       //On extrait le livre de la BDD grâce au nouveau titre
       livreFromBdd = livreBdd.getLivreWithTitre("J'ai modifié le titre du livre");
       //S'il existe un livre possédant ce titre dans la BDD
       if(livreFromBdd != null){
        //On affiche les nouvelle info du livre pour vérifié que le titre du livre a bien été mis à jour
        Toast.makeText(this, livreFromBdd.toString(), Toast.LENGTH_LONG).show();
        //on supprime le livre de la BDD grâce à son ID
    	livreBdd.removeLivreWithID(livreFromBdd.getId());
       }

      	//On essaie d'extraire de nouveau le livre de la BDD toujours grâce à son nouveau titre
       livreFromBdd = livreBdd.getLivreWithTitre("J'ai modifié le titre du livre");
       //Si aucun livre n'est retourné
       if(livreFromBdd == null){
       	//On affiche un message indiquant que le livre n'existe pas dans la BDD
       	Toast.makeText(this, "Ce livre n'existe pas dans la BDD", Toast.LENGTH_LONG).show();
       }
       //Si le livre existe (mais normalement il ne devrait pas)
       else{
       	//on affiche un message indiquant que le livre existe dans la BDD
       	Toast.makeText(this, "Ce livre existe dans la BDD", Toast.LENGTH_LONG).show();
       }*/

       livreBdd.close();
   }
}

Je sais qu'il y a beaucoup de commentaires, mais je ne préfère rien virer pour le moment, on ne sait jamais ^^'

Modifié par thefranchise
Lien vers le commentaire
Partager sur d’autres sites

Tout d'abord, merci de ta réponse Profete.

J'ai donc changé extends Activity par ListActivity et rajouté getListView().setAdapter(adapter)

Mais le programme plante (la fenêtre avec force close ><")

Le DDMS me dit

" Caused by: java.lang.RuntimeException: Your content must have a ListView whose id attribute is 'android.R.id.list'"

Or, ma listview définie dans le main.xml a bien comme "android:id="@+id/list"".

Lien vers le commentaire
Partager sur d’autres sites

Il faut mettre android:id="@+id/android:list"

Et accessoirement, il faudrait stocker dans un attribut l'instance de LivresBDD que tu instancies dans le onCreate, afin de n'appeler le close que dans la méthode onDestroy (sinon, ton accès BDD va être fermé dès la fin du onCreate, et ton adpater va avoir du mal à y accéder par la suite)

Lien vers le commentaire
Partager sur d’autres sites

J'ai modifié le android:id de ma ListView. maintenant je dois l'appeler comment ?

Car si je laisse

        SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.liste, c, new String[]{"titre"},new int[]{R.id.list});

il me dit une erreur. et idem en mettant R.id.android:list.

De plus, mon attribut "list" est effacé de ma classe id dans le fichier R.java.

Et accessoirement, il faudrait stocker dans un attribut l'instance de LivresBDD que tu instancies dans le onCreate, afin de n'appeler le close que dans la méthode onDestroy (sinon, ton accès BDD va être fermé dès la fin du onCreate, et ton adpater va avoir du mal à y accéder par la suite)

Qu'est ce que tu veux dire par stocker dans un attribut l'instance ? Une variable ?

Puis je ne vois pas il faut que je modifie mon id "list" en "android:list". Au début, j'avais fait une première fois un développement. ma page principale était une liste que je définissais. Je faisais donc appel à un simpleAdapter pour la créer. Et je n'ai eu aucun soucis avec les id =/; ils avaient bien la forme "list" et pas "android:list". le fait d'utiliser un simplecursorAdapter oblige d'avoir un certain type d'id ?

Modifié par thefranchise
Lien vers le commentaire
Partager sur d’autres sites

Dans ton code Java, il faut mettre android.R.id.list

Ce changement de nom d'id est nécessaire parce que ListActivity (dont ton Activity hérite) se base sur un identifiant bien défini pour retrouver la ListView dans ton layout (ce qui permet à la méthode getListView() de retourner la ListView qui va bien). Tu peux ne pas hériter de ListActivity, et dans ce cas ne pas être contraint sur l'id de ta ListView, mais tu perds le bénéfice apporté par ListActivity

Pour ce qui est de l'attribut pour stocker l'instance de la LivresBDD, je voulais dire que, au lieu de définir une variable livreBDD dans ta méthode onCreate, il faudrait définir un attribut livreBDD dans ta classe. Comme ceci:

public class test extends Activity {

   private LivresBDD livreBdd;  // Attribut pour stocker l'instance de LivresBDD

   /** Called when the activity is first created. */
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

       //Création d'une instance de ma classe LivresBDD, et stockage dans l'attribut défini plus haut
       livreBdd = new LivresBDD(this);

       //  blah blah blah

      // Enlever la fermeture de la BDD
      // livreBdd.close();
   }

   @Override
   protected void onDestroy()
   {
       if (livreBdd != null)
       {
           livreBdd.close();
       }
       super.onDestroy();
   }

}

Modifié par chpil
Lien vers le commentaire
Partager sur d’autres sites

J'ai réussi à ce qu'une liste s'affiche

Voici ma ListActivity de test :

package projet.bibliotheque;



import android.app.Activity;
import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.Toast;

public class test extends ListActivity {
   /** Called when the activity is first created. */
//private ListView ListeLivres;
private LivresBDD livreBdd;

   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

       //Création d'une instance de ma classe LivresBDD
       livreBdd=new LivresBDD(this);



       //On ouvre la base de données pour écrire dedans
       livreBdd.open();



       Cursor c = livreBdd.getAllLivre2();
       startManagingCursor(c);
       //mon erreur venait de là, je faisais R.layout.liste, au lieu de R.layout.list
       SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.list, c, new String[]{"titre"},new int[]{android.R.id.list});
       //ListeLivres = (ListView) findViewById(R.id.list);
       //ListeLivres.setAdapter(adapter);
       getListView().setAdapter(adapter);

   }

   @Override
   protected void onDestroy()
   {
       if (livreBdd != null)
       {
           livreBdd.close();
       }
       super.onDestroy();
   }
}

problème, ma liste s'affiche...mais elle est vide :/

screenlisteandroid.jpg

et comme vous le voyez, il y a un grand nombre d'éléments :x

Vous savez à quoi c'est dû ?

Modifié par thefranchise
Lien vers le commentaire
Partager sur d’autres sites

En y regardant de plus près, je dirais que ça vient des paramètres du SimpleCursorAdapter, qui ne sont pas corrects

Tu devrais plutôt avoir ceci:

       SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.list, c, new String[]{"titre"},new int[]{R.id.titreLivre});

(les deux derniers paramètres permettent de faire le parallèle entre les noms des colonnes issues de ta bdd, et le nom des View de ton layout dans lesquels sera affiché le contenu des colonnes de la base)

Lien vers le commentaire
Partager sur d’autres sites

\o/

Un grand merci chpil ça marche !

Bon par contre maintenant j'ai la masse de livres dans ma liste, vu que j'ai fait X essais. Faudra j'en supprime quelques uns ^^'

J'espère ne pu trop avoir à vous importuner avec mes questions ^^'

Euh comment on met un tag résolu ? ^^'

Modifié par thefranchise
Lien vers le commentaire
Partager sur d’autres sites

Mwarf suite du problème (je recréé pas de nouveau topic ?)

ma liste s'affiche bien, et j'aimerais que lorsque je clique sur un élément de ma liste (qui est donc un livre :P), ses informations (auteur, editeur etc) s'affichent dans un toast.

Mais je n'arrive pas à récupérer son titre :(. Enfin...quelque soit l'élément sur lequel je clique, il me récupère le titre du tout premier élément.

Voici à quoi ressemble ma classe :

package projet.bibliotheque;



import java.util.HashMap;

import android.app.Activity;
import android.app.ListActivity;
import android.database.Cursor;
import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.SimpleCursorAdapter;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.AdapterView.OnItemClickListener;

public class test extends ListActivity {
   /** Called when the activity is first created. */
//private ListView ListeLivres;
private LivresBDD livreBdd;
private TextView monTitre;
   @Override
   public void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.main);

       //Création d'une instance de ma classe LivresBDD
       livreBdd=new LivresBDD(this);

       //On ouvre la base de données pour écrire dedans
       livreBdd.open();

       Cursor c = livreBdd.getAllLivre2();
       startManagingCursor(c);
       //pour mettre un autre élément, rajouter un textview dans list
       SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, R.layout.list, c, new String[]{"titre"},new int[]{R.id.titreLivre});
       getListView().setAdapter(adapter);

     //Enfin on met un écouteur d'évènement sur notre listView
      getListView().setOnItemClickListener(new OnItemClickListener() {
       	@Override
       	@SuppressWarnings("unchecked")
        	public void onItemClick(AdapterView<?> a, View v, int position, long id) {
       		//on récupère la HashMap contenant les infos de notre item 
       		//final HashMap<String, String> map = (HashMap<String, String>) getListView().getItemAtPosition(position);
       		//String titre = map.get("titre");

       		final TextView monTitre = (TextView) findViewById(R.id.titreLivre);
       		//Toast.makeText(test.this, "titre : "+monTitre.getText(), Toast.LENGTH_LONG).show();
               Livre livreFromBdd = livreBdd.getLivreWithTitre((String) monTitre.getText());

               if(livreFromBdd != null){
               //On affiche les infos du livre dans un Toast
               Toast.makeText(test.this, livreFromBdd.toString(), Toast.LENGTH_LONG).show();
               }
       	}
       });

   }

   @Override
   protected void onDestroy()
   {
       if (livreBdd != null)
       {
           livreBdd.close();
       }
       super.onDestroy();
   }
}

Dites le moi si il faut que je recréé un nouveau sujet, je supprimerai ce message ^^

Modifié par thefranchise
Lien vers le commentaire
Partager sur d’autres sites

Personne ? :(

Minute papillon ! Quelle impatience...

La méthode onItemClick prend en paramètre un id, qui correspond à l'id, dans la base de données, de l'élément cliqué. Tu peux donc t'en servir pour récupérer les données complètes de la base

 public void onItemClick(AdapterView<?> a, View v, int position, long id) {

   Livre livreFromBdd = livreBdd.getLivreFromId(id); // implémenter getLivreFromId pour qu'elle retourne un Livre à partir de son id

   if (livreFromBdd != null){
     //On affiche les infos du livre dans un Toast
     Toast.makeText(test.this, livreFromBdd.toString(), Toast.LENGTH_LONG).show();
   }
 }

Lien vers le commentaire
Partager sur d’autres sites

Bonjour bonjour.

Je reviens vers vous pour la dernière fois (logiquement ^^').

Mon application marche en soi. Juste j'essaye de faire quelques modifs pour grapiller des points ^^'

Par exemple, pour ma page d'ajout (ou de suppression) j'aimerais tester ma requête. En gros, dire que si l'ajout (ou la suppression) a réussi, j'affiche un toast.

Voici mon code (ici ça concerne le click sur un bouton OK d'un alert pour la suppression...mais vou avez du le deviner ^^')

public void onItemClick(AdapterView<?> a, View v, int position, long id) {

        		//on récupère le livre en fonction de l'id de l'élément sur lequel on clique
                Livre livreFromBdd = livreBdd.getLivreWithId((int) id);

                //on récupère l'id du livre à supprimer
               final int idADelete = (int) id;

               //on créer une boite de dialogue
        		AlertDialog.Builder adb = new AlertDialog.Builder(suppression.this);
        		//on attribut un titre à notre boite de dialogue
       		adb.setTitle("suppression");
       		//on insère un message à notre boite de dialogue, et ici on affiche le titre de l'item cliqué
       		adb.setMessage("Voulez-vous supprimer : "+livreFromBdd.getTitre());
       		//on indique que l'on veut le bouton ok à notre boite de dialogue
       		adb.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
       			public void onClick(DialogInterface dialog, int id)
       			{        			                    
                       Livre livreFromBdd = livreBdd.getLivreWithId(idADelete);
                       String titreDelete = livreFromBdd.getTitre();
       				livreBdd.removeLivreWithID(idADelete);
       				if(livreBdd.removeLivreWithID(idADelete)==1)
       				{
       	                 Toast.makeText(suppression.this, "Le livre "+titreDelete+" a été supprimé" , Toast.LENGTH_LONG).show();
       				}
       				//on recharge la page pour voir la suppression
       				Intent nextActivity = new Intent(suppression.this, suppression.class);
               		startActivity(nextActivity);
       			}
       		});
       		adb.show();                
            	}
            });

le livre se supprime, mais le toast ne s'affiche pas. Comment peut on tester l'exécution de la requête et parvenir à afficher le toast ? :/

Edit : question alakon.

Je récupère une chaine

final String titre = editTextTitre.getText().toString();

pour tester si elle est vide je fais :

if (titre.equals(" "))

. Mais même si je met un espace dans le champ titre, le prog ne rentre pas dans la boucle. J'ai testé avec titre.length()==0 et titre.equals("") mais toujours rien :/.

Au pire si ce n'est pas résolu, ce n'est pas trop trop grave, c'est juste pour essayer d'améliorer un peu l'appli ^^

Modifié par thefranchise
Lien vers le commentaire
Partager sur d’autres sites

                                        livreBdd.removeLivreWithID(idADelete);
                                       if(livreBdd.removeLivreWithID(idADelete)==1)

Ben, en faisant cela, tu fais deux la suppression de ton livre, et comme tu ne testes le résultat que la deuxième fois, c'est normal qu'il te dise qu'il n'a rien supprimer vu que le livre est déjà supprimé

   int resSuppr = livreBdd.removeLivreWithID(idADelete);
   if (resSuppr == 1)

a plus de chance de fonctionner

                                       //on recharge la page pour voir la suppression
                                       Intent nextActivity = new Intent(suppression.this, suppression.class);
                               startActivity(nextActivity);

Ouh la la, tu vas avoir des surprises... Là, tu ne réaffiches pas réellement ton Activity, tu demandes la création d'une nouvelle instance de ton Activity, mais l'ancienne reste toujours en mémoire puisque non fermée... Tu empiles plusieurs Activities. Et si tu fais un back, tu reviendras sur la précédente instance, etc...

Dans ton cas, pas la peine de réouvrir l'Activity, il suffit de demander le raffraichissement de l'affichage de ses données. Et comme tu as un Adapter, il y a une méthode pour cela sur les Adapter : notifyDataChanged

Pour tester la chaine de caractère vide ou non, tu peux utiliser la méthode trim() qui permet de supprimer les espaces en début/fin de chaine. Ton test d'égalité avec la chaine vide fonctionnera alors ensuite, même si l'utilisateur saisit des espaces

final String titre = editTextTitre.getText().toString();
if (titre.equals(""))

Lien vers le commentaire
Partager sur d’autres sites

Encore merci à toi chpil (je l'aurais jamais dit autant en si peu de temps à la même personne ^^)

Pour le notifyDataSetChanged (notifyDataChanged n'apparait pas dans la liste des fonctions que je peux appliquer à mon adapter) je n'ai pas réussi à le faire fonctionner. J'ai réussi néanmoins à ce que le formulaire se rafraichisse en refaisant une sélection de ma table, récupérée dans un curseur, et en réappliquant un adapter à ma listView

public void onClick(DialogInterface dialog, int id)
       			{        			                    
       				//on sélectionne le livre à supprimer puis on récupère son titre.
                      Livre livreFromBdd = livreBdd.getLivreWithId(idADelete);
                      String titreDelete = livreFromBdd.getTitre();

                      //on supprime le livre
       				int resSuppr = livreBdd.removeLivreWithID(idADelete);

       				//si suppression, affichage d'un toast de confirmation
       				if (resSuppr == 1)
       				{
                           Toast.makeText(Suppression.this, "Le livre "+titreDelete+" a été supprimé" , Toast.LENGTH_LONG).show();
       				}

       				//on resélectionne les livres de la BD pour afficher la nouvelle liste.
       				Cursor c = livreBdd.getAllLivre2();
       		        startManagingCursor(c);
         		        SimpleCursorAdapter adapter = new SimpleCursorAdapter(Suppression.this, R.layout.list, c, new String[]{"titre"},new int[]{R.id.titreLivre});

       		        //on applique l'adapter à la liste
       		        getListView().setAdapter(adapter);
       				//adapter.notifyDataSetChanged();
       			}
       		});

Par contre je n'arrive toujours pas à tester ma chaine titre. Je fais ça, mais ça ne marche toujours pas :/

final String titre = editTextTitre.getText().toString();
if (titre.trim().equals(""))

edit : J'avais juste oublié de ne pas laisser adb.show() en commentaire -_-''' perdre du temps là-dessus j'vous jure...

Merci pour tes explications et tes conseils en tout cas chpil ;)

Modifié par thefranchise
Lien vers le commentaire
Partager sur d’autres sites

  • 4 months later...

Rejoignez la conversation

Vous pouvez poster maintenant et vous enregistrez plus tard. Si vous avez un compte, connectez-vous maintenant pour poster.

Invité
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Répondre à ce sujet…

×   Collé en tant que texte enrichi.   Coller en tant que texte brut à la place

  Seulement 75 émoticônes maximum sont autorisées.

×   Votre lien a été automatiquement intégré.   Afficher plutôt comme un lien

×   Votre contenu précédent a été rétabli.   Vider l’éditeur

×   Vous ne pouvez pas directement coller des images. Envoyez-les depuis votre ordinateur ou insérez-les depuis une URL.

×
×
  • Créer...