IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Android Discussion :

AutoCompleteTextView & onItemClick


Sujet :

Android

  1. #1
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut AutoCompleteTextView & onItemClick
    Salut!

    Un truc totalement surréaliste (au moins pour moi!) me faisant tourner en bourrique!

    Contexte:
    -> un champ AutoCompleteTextView ville
    -> utilisant une List:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    List<String> listeAffichageVille = new ArrayList<String>();
    -> elle même initialisée dans onTextChanged par une requête Php dans un thread (à cause des accès réseaux)
    -> à partir du 4ème caractère saisi, le champ ville propose des items de listeAffichage
    -> onItemClick récupère l'item de la position clickée
    Ok.....

    Là ou ça se corse:
    1er point, déjà louche: le thread de remplissage de la liste est relancé par le onItemClick une fois de plus(???)

    et ensuite, son comportement n'est pas identique, il ramène de 1 à n lignes, alors qu'on ne clique que sur une seule ligne des propositions faites!

    C'est vraiment compliqué à expliquer, et je ne sais pas si je suis clair, alors essayons des exemples:

    ex1:
    -> je tape MARS, ville me propose donc des villes connues de Php débutant par MARS
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    12-11 11:11:06.850: E/Thread-----------> 0(6257): Mars (Ardèche, Rhône-Alpes)
    12-11 11:11:06.850: E/Thread-----------> 1(6257): Mars (Dordogne, Aquitaine)
    12-11 11:11:06.850: E/Thread-----------> 2(6257): Mars (Gard, Languedoc-Roussillon)
    12-11 11:11:06.850: E/Thread-----------> 3(6257): Mars (Loire, Rhône-Alpes)
    12-11 11:11:06.850: E/Thread-----------> 4(6257): Marsa (Aude, Languedoc-Roussillon)
    12-11 11:11:06.850: E/Thread-----------> 5(6257): Marsac (Charente, Poitou-Charentes)
    12-11 11:11:06.850: E/Thread-----------> 6(6257): Marsac (Creuse, Limousin)
    12-11 11:11:06.850: E/Thread-----------> 7(6257): Marsac (Gironde, Aquitaine)
    12-11 11:11:06.850: E/Thread-----------> 8(6257): Marsac (Hautes-Pyrénées, Midi-Pyrénées)
    12-11 11:11:06.850: E/Thread-----------> 9(6257): Marsac (Tarn-et-Garonne, Midi-Pyrénées)
    12-11 11:11:06.850: E/Thread-----------> 10(6257): Marsal (Dordogne, Aquitaine)
    12-11 11:11:06.850: E/Thread-----------> 11(6257): Marsal (Moselle, Lorraine)
    12-11 11:11:06.850: E/Thread-----------> 12(6257): Marsal (Tarn, Midi-Pyrénées)
    12-11 11:11:06.850: E/Thread-----------> 13(6257): Marsal (Rhône-Alpes)
    12-11 11:11:06.850: E/Thread-----------> 14(6257): Marsan (Creuse, Limousin)
    12-11 11:11:06.850: E/Thread-----------> 15(6257): Marsan (Gers, Midi-Pyrénées)
    12-11 11:11:06.850: E/Thread-----------> 16(6257): Marsan (Loiret, Centre)
    12-11 11:11:06.850: E/Thread-----------> 17(6257): Marsan (Rhône-Alpes)
    12-11 11:11:06.850: E/Thread-----------> 18(6257): Marsas (Gironde, Aquitaine)
    12-11 11:11:06.850: E/Thread-----------> 19(6257): Marsas (Hautes-Pyrénées, Midi-Pyrénées)
    -> je sélectionne "Mars (Gard)", le thread est relancé et ramène
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    12-11 11:11:11.410: E/Thread-----------> 0(6257): Mars (Ardèche, Rhône-Alpes)
    12-11 11:11:11.410: E/Thread-----------> 1(6257): Mars (Dordogne, Aquitaine)
    12-11 11:11:11.410: E/Thread-----------> 2(6257): Mars (Gard, Languedoc-Roussillon)
    12-11 11:11:11.410: E/Thread-----------> 3(6257): Mars (Loire, Rhône-Alpes)
    DONC 4 lignes...

    ex2: (toujours le même code source of course!)
    -> je tape MULH, ville me propose donc des villes connues de Php débutant par MULH
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    12-11 11:11:26.930: E/Thread-----------> 0(6257): Mulheim (Province de Limbourg)
    12-11 11:11:26.930: E/Thread-----------> 1(6257): Mulhouse (Haut-Rhin, Alsace)
    12-11 11:11:26.930: E/Thread-----------> 2(6257): Mulhausen (Bas-Rhin, Alsace)
    -> je sélectionne "Mulhouse (Haut Rhin), le thread est relancé et ramène
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    12-11 11:11:28.340: E/Thread-----------> 0(6257): Mulhouse (Haut-Rhin, Alsace)
    DONC 1 ligne........

    ex3: (toujours le même code source of course!)
    -> je tape PERR, ville me propose donc des villes connues de Php débutant par PERR
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    12-11 11:34:01.310: E/Thread-----------> 0(6825): Perre (Indre-et-Loire, Centre)
    12-11 11:34:01.310: E/Thread-----------> 1(6825): Perre (Flandre Orientale)
    12-11 11:34:01.310: E/Thread-----------> 2(6825): Perran (Bretagne)
    12-11 11:34:01.310: E/Thread-----------> 3(6825): Perray (Indre-et-Loire, Centre)
    12-11 11:34:01.310: E/Thread-----------> 4(6825): Perret (Côtes-d'Armor, Bretagne)
    12-11 11:34:01.310: E/Thread-----------> 5(6825): Perret (Rhône-Alpes)
    12-11 11:34:01.310: E/Thread-----------> 6(6825): Perrex (Ain, Rhône-Alpes)
    12-11 11:34:01.310: E/Thread-----------> 7(6825): Perros (Finistère, Bretagne)
    12-11 11:34:01.310: E/Thread-----------> 8(6825): Perros (Finistère, Bretagne)
    12-11 11:34:01.310: E/Thread-----------> 9(6825): Perros (Bretagne)
    12-11 11:34:01.310: E/Thread-----------> 10(6825): Perrou (Orne, Basse-Normandie)
    12-11 11:34:01.310: E/Thread-----------> 11(6825): Perroy (Nièvre, Bourgogne)
    12-11 11:34:01.310: E/Thread-----------> 12(6825): Perroy ()
    12-11 11:34:01.310: E/Thread-----------> 13(6825): Perreux (Loire, Rhône-Alpes)
    12-11 11:34:01.310: E/Thread-----------> 14(6825): Perreux (Yonne, Bourgogne)
    12-11 11:34:01.310: E/Thread-----------> 15(6825): Perrier (Dordogne, Aquitaine)
    12-11 11:34:01.310: E/Thread-----------> 16(6825): Perrier (Puy-de-Dôme, Auvergne)
    12-11 11:34:01.310: E/Thread-----------> 17(6825): Perruel (Eure, Haute-Normandie)
    12-11 11:34:01.310: E/Thread-----------> 18(6825): Perrelli (Corse)
    12-11 11:34:01.310: E/Thread-----------> 19(6825): Perreuil (Saône-et-Loire, Bourgogne)
    -> je sélectionne "Perret (Côtes-d'Armor)" (le 5ème de la liste, indice 4 donc), le thread est relancé et ramène
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    12-11 11:34:26.750: E/Thread-----------> 0(6825): Perret (Côtes-d'Armor, Bretagne)
    12-11 11:34:26.750: E/Thread-----------> 1(6825): Perret (Rhône-Alpes)
    DONC 2 lignes cette fois-ci........
    -> et BOUM!
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    java.lang.IndexOutOfBoundsException: Invalid index 4, size is 2
    puisque l'indice récupéré par onItemClick est le bon, 4 ici.... mais comme le thread est relancé au moment du onItemClick et qu'il ne ramène que 2 lignes, on est hors index!


    Pourquoi ça me gène
    -> d'abord parce que je ne trouve pas ce comportement normal
    -> et ensuite, surtout parce que parfois, la position ramenée par onItemClick n'est pas la bonne, et donc crache l'appli (java.lang.IndexOutOfBoundsException) pour un mauvais index.
    -> le tout étant "aléatoire" puisque durant mon dev je testais avec 1 ou 2 villes, toujours les mêmes, et RAS
    -> là j'arrive au bout, donc je teste un peu plus "intensément".... et c'est là que je me rend compte du problème....

    Ai-je réussi à me faire comprendre par ces exemples?

    Une idée peut être?
    Qu'est ce qui m'échappe?

    Merci.

  2. #2
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    PRECISION:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    public void onItemClick(AdapterView<?> parent, View arg1, int position, long id) 
    {
    idClickedVille = a_idVil.get(position);
    }
    avec la globale
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    private ArrayList<String> a_idVil = new ArrayList<String>();
    qui stocke en // les ID des villes de la liste... et c'est cet ID que je dois récupérer

  3. #3
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Je ne vois rien d'aléatoire, il récupère systématiquement les villes qui commencent par le texte entré jusqu'au premier espace...

    Maintenant, on a comment cela se passe.... il faudrait voir comment c'est fait ^^ un peu de code (le thread de remplissage, le 'onItemClick', le onTextChanged et surtout la requête en base de donnée).

    D'autre part, tu parles très souvent "d'index", c'est une valeur facétieuse en informatique les index Il vaut mieux conserver des références uniques qu'un truc qui change à chaque insert (comme tu le dis l'index change, et en plus de manière asynchrone avec un thread, donc on ne sait pas trop quand).

    Je ne sais pas si tu as un identifiant unique... mais par exemple conserver un truc genre:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    class VilleReference
    {
        long    id;
        String display;
     
        public long getId() { return this.id; }
        public String getDisplay() { return this.display; }
        public void setId(long i) { this.id = i; }
        public void setDisplay(String t) { this.display = t; }
     
        public String toString() { return this.display; }
    }
    Et dès qu'on recoit un click, conserver CETTE référence là (on a tout, l'ID en BDD, et le texte) éviterait déjà des conversions d'index perilleuses lors de changements de la liste.
    Bien sur si il n'y a pas d'identifiant 'numérique' en base de donnée, c'est la chaine complète qu'il faut stocker...

  4. #4
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    Le problème serait donc l'espace?
    -> dans ce cas on aurait le même plantage pour BORD & MARS

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
     
    private Integer errorMsgId;
    private String  errorMsgParam;
    private List<String> listeAffichageVille = new ArrayList<String>();
    private ArrayList<String> a_idVil = new ArrayList<String>();
    private int villePosition = -1;
    private String idClickedVille = "";
     
    public void onTextChanged(CharSequence s, int start, int before, int count) 
    {    	
    	if (ville.enoughToFilter())		//REQUETE uniquement à partir de 'n' caractères saisis (threshold = 4 ici dans .XML)!
        	{    		
    	    	builtURL = CONFIG_UNIQ_ID + separateur + String.valueOf(VILLE + separateur + ville.getText());
    	    	RemplirVille2 thread;
    			try 
    			{
    				thread = new RemplirVille2(BASE_URL4 + URLEncoder.encode(Fonctions.cryptage3DES(builtURL),"UTF-8"));
    				thread.start();
    			    while (thread.isAlive())
    			    {
    			    	//rien, juste attendre fin thread pour envoyer la liste à l'adapter
    			    	SystemClock.sleep(1);		    	
    			    }
    			} 
    			catch (UnsupportedEncodingException e) 
    			{
    				e.printStackTrace();
    			}
     
    		    //bloc équivalent au onPostExecute d'Async
    		    //****************************************
    		    if (listeAffichageVille == null)	//si NULL alors problème...
    			{
    				  if (errorMsgId != null) 
    			      {
                          String msg = this.getString(this.errorMsgId);
                          Toast.makeText(this,msg,Toast.LENGTH_LONG).show();
    			      }    
    			}
    			else				//.. SINON affecter les data à l'adapter! 
    			{
    				ville.setAdapter(new ArrayAdapter<String>(this,android.R.layout.simple_selectable_list_item,listeAffichageVille));
    				//DEBUG
    				int i = 0, j = 0;
    				for (String s1 : listeAffichageVille)	{ Log.e("onTextChanged-----------> " + i,s1); i++;}
    				for (String s2 : a_idVil)				{ Log.e("onTextChanged-----------> " + j,s2); j++;}				
    			}
        	}
    }
    ET
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
     
    class RemplirVille2 extends Thread
    {
        	private String URL;
        	private int return_code;
     
        	public int getValue() 				{ return return_code; }
            public RemplirVille2(String url)	{ this.URL = url; }
     
        	public void run() 
        	{
    	    	ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
     
    	    	try 
    			{
    	    		 	 HttpClient httpclient = new DefaultHttpClient();
    	    		 	 final HttpParams httpParams = httpclient.getParams();
    	    		 	 HttpConnectionParams.setConnectionTimeout(httpParams, CONFIG_TIMEOUT_RESEAU);
    	    		 	 HttpConnectionParams.setSoTimeout(httpParams, CONFIG_TIMEOUT_RESEAU);
    	    		 	 HttpPost httppost = new HttpPost(URL);
    	    		 	 httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs)); 
     
    	    		 	 HttpResponse response = httpclient.execute(httppost);
     
                         if (response.getStatusLine().getStatusCode() < 400) 
    					 {
     
                        	  HttpEntity entity = response.getEntity();
                              String encodedArray = EntityUtils.toString(entity);
                              String decodedArray = Fonctions.decryptagePassword3DES(encodedArray,CONFIG_CLE_DATA_CRYPTE);
                              JSONArray json_array = new JSONArray(decodedArray);
     
                              listeAffichageVille.clear();		//IMPORTANTISSIME!!! vider avant chaque remplissage, sinon data APPEND!!!
                              a_idVil.clear();
     
                              for(int i=0;i<json_array.length();i++) 
    						  {
                                  JSONObject json_ligne = json_array.getJSONObject(i);   
                                  listeAffichageVille.add(json_ligne.getString("VILLE"));
                                  a_idVil.add(json_ligne.getString("CLEF_VILLE"));
                                  return_code = 1;   
    						  }
     
                              //DEBUG
                              int i = 0, j = 0;
                              for (String s1 : listeAffichageVille) { Log.e("Thread-----------> " + i,listeAffichageVille.get(i)); i++; }
                              for (String s2 : a_idVil)             { Log.e("Thread-----------> " + j,a_idVil.get(j)); j++; }
    					} 
    					else 
    					{
    						Log.e("THREAD RemplirVille2: EXCEPTION http error ", "--"+response.getStatusLine().toString()+"--"); 
                            errorMsgId = R.string.http_site_error;
                            listeAffichageVille = null;
                            return_code = -1;
                        }
    	        } 
    			catch (Exception ex) 
    			{
                		Log.e("THREAD RemplirVille2: EXCEPTION decode error", "--"+ex.toString()+"--");
                        errorMsgId = R.string.http_decode_error;
                        errorMsgParam = ex.getLocalizedMessage();
                        listeAffichageVille = null;
                        return_code = -1;
                }  
        	}
    }
    PS: désolé pour les indentations pourries, mais si qq'un à une astuce pour 1 copy/paste efficace de ce point de vue là, je prends aussi!

  5. #5
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Déjà: ca:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    				thread = new RemplirVille2(BASE_URL4 + URLEncoder.encode(Fonctions.cryptage3DES(builtURL),"UTF-8"));
    				thread.start();
    			    while (thread.isAlive())
    			    {
    			    	//rien, juste attendre fin thread pour envoyer la liste à l'adapter
    			    	SystemClock.sleep(1);		    	
    			    }
    Pourquoi faire un thread dans ce cas ? ... Autant le faire directement ça sera plus rapide (la création d'un thread c'est long).


    Bon... il manque le 'onClick'... mais ma boule de cristal m'a montré une image.... le onClick va changer le texte, et du coup, appeler le onTextChanged() .... ce qui expliquerait pourquoi le thread (enfin ... la fonction en l’occurrence) est appelée par le onClick...

    Du "Log.i()" ou "Log.v()" de temps à autre aiderait à comprendre le déroulement exactement.
    Attention aux Log.e() aussi:
    Log.e("THREAD RemplirVille2: EXCEPTION decode error", "--"+ex.toString()+"--");
    Ne veut rien dire... le tag devrait permettre de trouver rapidement les logs concernant un bout de code (par exemple "THREAD RemplirVille2"), le message, ben c'est le message.... l'exception doit être passée en dernier paramètre !
    Donc:
    Log.e("THREAD RemplirVille2","EXCEPTION decode error",ex);


    Je reviens tout à l'heure....

  6. #6
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    Déjà: ca:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    				thread = new RemplirVille2(BASE_URL4 + URLEncoder.encode(Fonctions.cryptage3DES(builtURL),"UTF-8"));
    				thread.start();
    			    while (thread.isAlive())
    			    {
    			    	//rien, juste attendre fin thread pour envoyer la liste à l'adapter
    			    	SystemClock.sleep(1);		    	
    			    }
    Pourquoi faire un thread dans ce cas ? ... Autant le faire directement ça sera plus rapide (la création d'un thread c'est long).
    ben(?), simplement parce qu'on ne peut pas faire d'accès réseau dans le UI.
    -> je trouve le wait très moyen
    -> mais en attendant de trouver mieux...

    Bon... il manque le 'onClick'... mais ma boule de cristal m'a montré une
    non, je ne l'ai juste pas re-posté puisque je l'avais déjà fait avant

    image.... le onClick va changer le texte, et du coup, appeler le onTextChanged() .... ce qui expliquerait pourquoi le thread (enfin ... la fonction en l’occurrence) est appelée par le onClick...
    oui MAIS en faisant un clic, tu en sélectionnes qu'une seule ligne dans la liste..... donc pourquoi en renvoyer 4, ou 2 au lieu de simplement ramener celle que tu as choisis quoi?

    Du "Log.i()" ou "Log.v()" de temps à autre aiderait à comprendre le déroulement exactement.
    moi j'en ai, c'est comme ça que j'ai compris ce qui se passait.
    je les ai juste virés ici par soucis de clarté.

    Attention aux Log.e() aussi:
    Log.e("THREAD RemplirVille2: EXCEPTION decode error", "--"+ex.toString()+"--");
    Ne veut rien dire... le tag devrait permettre de trouver rapidement les logs concernant un bout de code (par exemple "THREAD RemplirVille2"), le message, ben c'est le message.... l'exception doit être passée en dernier paramètre !
    Donc:
    Log.e("THREAD RemplirVille2","EXCEPTION decode error",ex);
    ok


    PS:
    - la requête en base, elle, renvoie bien ce qu'il faut, c'est vérifié.
    - le plus simple serait de ne pas (re)lancer le thread sur le onClick, mais comment?
    - pkoi je gère un tableau d'ID à coté de la liste de libellés? parce que si j'inclus les ID (et je parle bien d'ID, pas d'index) aux libellés, on verra aussi les ID à l'affichage de la liste.

  7. #7
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    Bref, tout ça c'est MA solution/vision de débutant... pas forcément optimale par définition... donc si on peut faire mieux, pas de soucis, je n'ai rien contre l'apprentissage.

    Ce que je pensais que ça ferait:
    onTextChanged() --> thread --> affichage liste --> <select ville dans liste> --> onClick(), avec récupération de l'indice de la ville clickée = int position

    Ce que ça fait vraiment:
    onTextChanged() --> thread --> affichage liste --> <select ville dans liste> --> onTextChanged() --> thread --> onClick() MAIS avec la valeur int position de <select ville dans liste> (ex3 ci-dessus: 20 items) et non du 2ème passage dans thread (ex3 ci-dessus: 2 items)

  8. #8
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    ben(?), simplement parce qu'on ne peut pas faire d'accès réseau dans le UI.
    Oui, parce qu'on ne peut pas ATTENDRE dans le thread UI, que ce soit par une attente IO de réseau, ou par un simple 'sleep()' !


    Voici un 'exemple' d'implémentation, je n'ai pas vérifié si cela compilait/marchait, juste l'idée de base....

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
     
    class MyActivity extends Activity implements AdapterView.OnItemClickListener
    {
        // on garde des données cohérentes... peu importe si cela complexifie certaines parties du code, les bugs disparaitront comme par magie 
        static class Ville {
            String id;
            String name;
     
            @Override
            public String toString() { return this.name; }
        };
     
     
     
        ArrayAdapter<Ville>  villeAdapter;
        String                     villeAdapterFilter;
        VilleUpdateTask        villeAdapterUpdateTask;
        AutoCompleteTextView villeText;
     
        Ville                       selectedVille;
     
     
        final TextWatcher textChecker = new TextWatcher() {
     
            public void afterTextChanged(Editable s) {}
     
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {}
     
            public void onTextChanged(CharSequence s, int start, int before, int count)
            { 
                  MyActivity.this.setAdapterFilter(s.toString());
            }
     
        };
     
        public void onCreate(Bundle bundle)
        {
             super.onCreate(bundle);
             setContentView(R.layout.xxxxxx);
     
             // au début, l'adapter est vide....
             this.villeAdapter = new ArrayAdapter<Ville>(this,android.R.layout.simple_dropdown_item_1line, new Ville[0]);
              // on setup le textview
             this.villeText = (AutoCompleteTextView ) findViewById(R.id.villeSelector);
             this.villeText.setAdapter(this.villeAdapter);
             this.villeText.setThreshold(THRESHOLD_DROPDOWN); 
             this.villeText.setOnItemClickListener(this);
             this.villeText.addTextChangedListener(textChecker);
        }
     
        public void onDestroy() {
             stopVilleAdapterUpdate();
        }
     
     
        public void setAdapterFilter(String filter)
        {
             if (filter == null) {
                 // clearing the adapter
                 this.villeAdapterFilter = null;
                 this.villeAdapter.clear();
                 this.villeAdapter.notifyDataSetChanged();
                 Log.d("MyActivity","Clearing ville filter !");
             } else if (filter.length() > THRESHOLD_QUERY) {
                  if (this.villeAdapterFilter == null) {
                      Log.d("MyActivity","Ville Adapter Filter defined to:"+filter);
                      this.villeAdapterFilter = filter;
                      startVilleAdapterUpdate();
                  } else {
                      Log.d("MyActivity","Already filtered with:"+this.villeAdapterFilter);
                  }
             } else {
                  Log.d("MyActivity","Resetting filter (not enough data)");
                  this.villeAdapterFilter = null;
                 this.villeAdapter.clear();
                 this.villeAdapter.notifyDataSetChanged();
             }
        }
     
        public synchronized void onItemClick(ViewAdapter<?> ad, View v, int position, long id)
        {
             this.selectedVille = this.villeAdapter.getItemAtPosition(position);
             Log.d("MyActivity","Ville selected: "+this.selectedVille);
        }
     
        public synchronized void startVilleAdapterUpdate()
        {
              stopVilleAdapterUpdate();
              Log.d("MyActivity","Starting Update of Villes with "+this.villeAdapterFilter);
              this.villeAdapterUpdateTask = new VilleUpdateTask();
              this.villeAdapterUpdateTask.execute(this.villeAdapterFilter);
        }
     
        public synchronized void stopVilleAdapterUpdate()
        {
             if (this.villeAdapterUpdateTask != null) {
                 Log.d("MyActivity","Stopping current update of villes");
                 this.villeAdapterUpdateTask.cancel(true);
                 this.villeAdapterUpdateTask = null;
             }
        }
     
        public synchronized void onVilleAdapterUpdateResult(Ville[] data)
        {
             this.villeAdapterUpdateTask = null;
             if (data != null) {
                 Log.d("MyActivity","Received "+data.length+" villes from update task");
                 this.villeAdapter.clear();
                 this.villeAdapter.addAll(data);
                 this.villeAdapter.notifyDataSetChanged(); // mise à jour du drop down...
            }
        } 
     
        class VilleUpdateTask extends AsyncTask<String,Void,Ville[]>
        {
              public Ville[] doInBackground(String ... filters)
              {
                  ArrayList<Ville> values = new ArrayList<Ville>();
                  try  {
                       HttpClient httpclient = new DefaultHttpClient();
                       ....
                       ....
                       for(int i=0;i<json_array.length();i++) {
                           JSONObject json_ligne = json_array.getJSONObject(i);   
                           try {
                               Ville v = new Ville();
                               v.name = json_ligne.getString("VILLE");
                               v.id = json_ligne.getString("CLEF_VILLE");
                               values.add(v);
                           } catch (Exception ex) {
                               Log.w("VilleUpdateTask","Invalid value for Ville at index #"+i,ex);
                           }
                       }
                  } catch (Exception ex) {
                       Log.e("VilleUpdateTask","Failed to retrieve list of Ville !",ex);
                  }
                  return values.toArray(new Ville[values.size()]);
             }
     
             public void onPostExecute(Ville[] data)
             {
                 MyActivity.this.onVilleAdapterUpdateResult(data);
             }
        }
     
    }
    EDIT: L'auto-complete va déjà limiter l'affichage à ce qui correspond de l'adapter.... Donc une fois qu'il est rempli, à priori, sauf si on supprime des caractères (en deçà du "threshold", pas besoin de refaire de requête). Du coup j'ai corrigé les fonctions....

  9. #9
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    Oulaaaa!
    Ca m'a l'air autrement plus compliqué oui.

    Je vais voir ça demain.
    Merci.

  10. #10
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    Marrant, j'aurais dit le contraire question complexitude

    Le code est bien séparé:

    Gestion de l'activité classique:
    onCreate/onDestroy

    Gestion du "filtre" de l'adapter
    setVilleAdapterFilter

    Gestion du "click" sur une ville
    onItemClick

    Gestion de l'update du contenu de l'adapter (thread à part)
    start/stop AdapterUpdate + onAdapterData()

  11. #11
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    J'espère que dans qq temps je penserai comme toi!

    Bon, bref, j'ai attaqué ma petite "cuisine" d'adaptation là et j'ai un soucis:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
        public synchronized void onItemClick(ViewAdapter<?> ad, View v, int position, long id)
        {
             this.selectedVille = this.villeAdapter.getItemAtPosition(position);
             Log.d("MyActivity","Ville selected: "+this.selectedVille);
     
             this.villeAdapterFilter = this.selectedVille.toString(); // évite que la tache soit relancée par le changement de texte
             // this.villeText.setText(this.selectedVille.toString()); // on a besoin de ça ? pas sur !
             // NB: en général, on quitte directement ici, puisqu'on a déjà la ville finale !
             // dans tous les cas, on ne conserve jamais la 'position'.
        }
    -> ViewAdapter cannot be resolved as a type
    -> the method is undefined

    alors que les imports de l'adapterview sont bien là

    EDIT:
    -> ok pour le 1er c'est AdapterView et non l'inverse, ça c'est bon!
    -> et getItem pour le 2ème

  12. #12
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    Alors verdict:

    Ta soluce fonctionne correctement, ça je n'en doutais pas ... sauf qu'au niveau ergonomie, les villes ne s'affichent qu'au fur et à mesure de la frappe:

    je tape PERR
    -> Perre (Indre & Loire)
    -> Perre (Flandres)

    je rajoute I
    -> Perrier (Dordogne)
    -> Perrier (Puy de Dôme)
    et ainsi de suite...

    Mon boss trouve que la mienne (affichage de toute la liste des xxxx, puis affinage selon 5è/6è/... lettre saisie) était plus pratique à l'usage.

    je tape PERR (j'ai tout de suite la liste complète de tous les PERR, qui s'affine à chq caractère de plus saisi)
    -> Perre (Indre & Loire)
    -> Perre (Flandres)
    -> Perran (Bretagne)
    -> Perray (Indre & Loire)
    -> Perret (Cotes d'Armor)
    -> Perret (Rhone Alpes)
    etc...


    J'ai donc essayé de voir chez toi où ça se jouait.
    Je n'ai pas encore trouvé en fait MAIS ton code m'a qd même inspiré qq chose:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    public synchronized void onItemClick(AdapterView<?> parent, View arg1, int position, long id)
    D'après mes 1ers tests, le tag synchronized ferait toute la différence sur mon code, puisque cette fois-ci le paramètre position de onClick() prend bien la bonne valeur de la liste du 2ème passsage dans le thread!

    Et non plus la position de la ville choisie au 1er passage, comme je l'expliquais ci-dessus:

    Ce que ça fait vraiment:
    onTextChanged() --> thread --> affichage liste --> <select ville dans liste> --> onTextChanged() --> thread --> onClick() MAIS avec la valeur int position de <select ville dans liste> (ex3 ci-dessus: 20 items) et non du 2ème passage dans thread (ex3 ci-dessus: 2 items)
    Je continue néanmoins de creuser/tester...

    EDIT:
    bon ben fausse alerte, l'effet d'un autre test qui trainait!
    retour dans ton code pour essayer de comprendre & trouver quoi modifier

  13. #13
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    Bon, je me perds là, donc questions:

    1.) possible de faire l'affichage de la liste complète (comme je faisais) dans ton code?

    2.) problème de synchro avec Async, comme j'avais déjà eu moi au départ
    -> liste proposée qu'à partir de threshold + 1
    -> je réécris en thread normal

  14. #14
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    En fait déjà... il y a 2 threshold....

    le premier est à partir de quand on va demander au webservice la liste... cette demande est réalisée dans une tâche asynchrone (le VilleUpdateTask ou un truc du genre), quand la tâche est finie, elle appelle l'UI en lui disant: "ok j'ai les données".
    Le second quand l'auto-complete va se mettre en marche... Ce qui permet de lancer la requete au caractère 'n', et d'avoir le temps d'appui sur le caractère suivant pour récupérer les villes (petite astuce pour faire croire que ça va vite ^^ )

    Le 'synchronized' ne sert à rien pour être honnête... puisque toutes les fonction de 'Activity' sont appelées dans le thread UI, il n'y a pas besoin à priori de les synchroniser.

    Par contre, la logique des auto-complete... je ne comprends pas trop pourquoi il n'afficherait que 2 éléments ??? La liste complete n'est chargée qu'une fois de toute manière, donc c'est le filtre de l'auto-complete qui doit merder quelque par...

    Ensuite, tu peux très bien remettre le code que j'avais au début à savoir:
    Stocker dans l'activité le "villeAdapterFilter" (String)
    Et demander un update (startVilleAdapterUpdate()) uniquement si le filtre est modifié par la fonction setVilleAdapterFilter()....
    Et on reviendra a ta solution (la tâche asynchrone en plus).

  15. #15
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    Citation Envoyé par nicroman Voir le message
    En fait déjà... il y a 2 threshold....

    le premier est à partir de quand on va demander au webservice la liste... cette demande est réalisée dans une tâche asynchrone (le VilleUpdateTask ou un truc du genre), quand la tâche est finie, elle appelle l'UI en lui disant: "ok j'ai les données".
    Le second quand l'auto-complete va se mettre en marche... Ce qui permet de lancer la requete au caractère 'n', et d'avoir le temps d'appui sur le caractère suivant pour récupérer les villes (petite astuce pour faire croire que ça va vite ^^ )
    et l'instruction this.villeText.setThreshold(3); gère lequel des deux alors?
    -> le 1er à priori
    -> donc qui/quoi commande le 2ème?

    Le 'synchronized' ne sert à rien pour être honnête... puisque toutes les fonction de 'Activity' sont appelées dans le thread UI, il n'y a pas besoin à priori de les synchroniser.
    oui, oui, j'ai vu que c'était une fausse piste, c'est pour ça que je suis repassé sur TON code en laissant le mien de coté.

    Par contre, la logique des auto-complete... je ne comprends pas trop pourquoi il n'afficherait que 2 éléments ??? La liste complete n'est chargée qu'une fois de toute manière, donc c'est le filtre de l'auto-complete qui doit merder quelque par...
    au départ je pensais que c'était un problème de tâche asynchrone... genre liste pas encore complètement chargée, pour ça que je parlais de réécrire en thread avec un wait, pour tester.

    et, hier soir dans la voiture, je me suis souvenu d'un truc que j'avais vu au début, à savoir qu'on peut rendre synchrone un Async avec un .get();
    -> l'histoire des 2 threshold dont tu parlais au départ?
    -> je suppose parce que si je tape 3 lettres, que j'en efface 1 pour la retaper, là j'ai la bonne liste en affichage

    Ensuite, tu peux très bien remettre le code que j'avais au début à savoir:
    comme je disais, je suis déjà sur ton code là, aucune modif si ce n'est le VilleUpdateTask() adapté pour récupérer mes data, mais c'est comme si l'affichage réagissait avec une lettre de retard

    Stocker dans l'activité le "villeAdapterFilter" (String)
    Et demander un update (startVilleAdapterUpdate()) uniquement si le filtre est modifié par la fonction setVilleAdapterFilter()....
    Et on reviendra a ta solution (la tâche asynchrone en plus).
    ??

    pour être honnête, je ne comprends pas toute la logique de ton code, des trucs flous...

    alors je continue de creuser d'ici que tu repasses, et je mettrai à jour au besoin.

  16. #16
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    Ok, je décompose un test "tel-quel", pour voir & poser les choses... ça m'aide souvent:

    contexte:
    -> threshold du onCreate à 3
    -> this.villeAdapterUpdateTask.execute(this.villeAdapterFilter).get();
    OU
    ->this.villeAdapterUpdateTask.execute(this.villeAdapterFilter);
    (peu importe, comportement identique dans les 2 cas)

    test1
    1.) je tape PER
    -> logcat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    12-13 09:30:48.910: D/MyActivity - filter(2817): Ville Adapter Filter changed:Per
    12-13 09:30:48.910: D/MyActivity - starting(2817): Starting Update of Villes with Per
    12-13 09:30:48.910: E/>>>********* ASYNC(2817): run
    12-13 09:30:49.160: E/*****************(2817): (Peri (Corse du Sud, Corse))
    12-13 09:30:49.160: E/*****************(2817): (Perk (Brabant Wallon))
    12-13 09:30:49.160: E/*****************(2817): (Pern (Lot, Midi-Pyrénées))
    12-13 09:30:49.160: E/*****************(2817): (Pers (Aveyron, Midi-Pyrénées))
    12-13 09:30:49.160: E/*****************(2817): (Pers (Cantal, Auvergne))
    12-13 09:30:49.160: E/*****************(2817): (Pers (Deux-Sèvres, Poitou-Charentes))
    12-13 09:30:49.160: E/*****************(2817): (Péry ())
    12-13 09:30:49.160: E/*****************(2817): (Péré (Charente-Maritime, Poitou-Charentes))
    12-13 09:30:49.160: E/*****************(2817): (Péré (Hautes-Pyrénées, Midi-Pyrénées))
    12-13 09:30:49.160: E/*****************(2817): (Perth (Ontario))
    12-13 09:30:49.160: E/*****************(2817): (Peray (Sarthe, Pays-de-la-Loire))
    12-13 09:30:49.160: E/*****************(2817): (Perce (Québec))
    12-13 09:30:49.160: E/*****************(2817): (Percy (Manche, Basse-Normandie))
    12-13 09:30:49.160: E/*****************(2817): (Peren (Province d'Anvers))
    12-13 09:30:49.160: E/*****************(2817): (Perlé (Diekirch))
    12-13 09:30:49.160: E/*****************(2817): (Perno (Loire-Atlantique, Pays-de-la-Loire))
    12-13 09:30:49.160: E/*****************(2817): (Peros (Finistère, Bretagne))
    12-13 09:30:49.160: E/*****************(2817): (Perre (Indre-et-Loire, Centre))
    12-13 09:30:49.160: E/*****************(2817): (Perre (Flandre Orientale))
    12-13 09:30:49.160: E/*****************(2817): (Péret (Hérault, Languedoc-Roussillon))
    12-13 09:30:49.170: I/MyActivity - received(2817): Received 20 villes from update task
    -> MAIS aucun affichage!

    2.) je supprime le R, et je le retape
    -> logcat vide
    -> MAIS liste des villes "Per*" bien affiché, avec un "temps" de retard donc

    test2
    1.) je tape PER
    -> logcat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    12-13 09:34:40.250: D/MyActivity - filter(2875): Ville Adapter Filter changed:Per
    12-13 09:34:40.250: D/MyActivity - starting(2875): Starting Update of Villes with Per
    12-13 09:34:40.250: E/>>>********* ASYNC(2875): run
    12-13 09:34:40.480: E/*****************(2875): (Peri (Corse du Sud, Corse))
    12-13 09:34:40.480: E/*****************(2875): (Perk (Brabant Wallon))
    12-13 09:34:40.480: E/*****************(2875): (Pern (Lot, Midi-Pyrénées))
    12-13 09:34:40.480: E/*****************(2875): (Pers (Aveyron, Midi-Pyrénées))
    12-13 09:34:40.480: E/*****************(2875): (Pers (Cantal, Auvergne))
    12-13 09:34:40.480: E/*****************(2875): (Pers (Deux-Sèvres, Poitou-Charentes))
    12-13 09:34:40.490: E/*****************(2875): (Péry ())
    12-13 09:34:40.490: E/*****************(2875): (Péré (Charente-Maritime, Poitou-Charentes))
    12-13 09:34:40.490: E/*****************(2875): (Péré (Hautes-Pyrénées, Midi-Pyrénées))
    12-13 09:34:40.490: E/*****************(2875): (Perth (Ontario))
    12-13 09:34:40.490: E/*****************(2875): (Peray (Sarthe, Pays-de-la-Loire))
    12-13 09:34:40.490: E/*****************(2875): (Perce (Québec))
    12-13 09:34:40.490: E/*****************(2875): (Percy (Manche, Basse-Normandie))
    12-13 09:34:40.490: E/*****************(2875): (Peren (Province d'Anvers))
    12-13 09:34:40.490: E/*****************(2875): (Perlé (Diekirch))
    12-13 09:34:40.490: E/*****************(2875): (Perno (Loire-Atlantique, Pays-de-la-Loire))
    12-13 09:34:40.490: E/*****************(2875): (Peros (Finistère, Bretagne))
    12-13 09:34:40.490: E/*****************(2875): (Perre (Indre-et-Loire, Centre))
    12-13 09:34:40.490: E/*****************(2875): (Perre (Flandre Orientale))
    12-13 09:34:40.490: E/*****************(2875): (Péret (Hérault, Languedoc-Roussillon))
    12-13 09:34:40.500: I/MyActivity - received(2875): Received 20 villes from update task
    -> MAIS aucun affichage!

    2.) je rajoute un R
    -> logcat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    12-13 09:35:20.820: D/MyActivity - filter(2875): Ville Adapter Filter changed:Perr
    12-13 09:35:20.820: D/MyActivity - starting(2875): Starting Update of Villes with Perr
    12-13 09:35:20.830: E/>>>********* ASYNC(2875): run
    12-13 09:35:21.150: E/*****************(2875): (Perre (Indre-et-Loire, Centre))
    12-13 09:35:21.150: E/*****************(2875): (Perre (Flandre Orientale))
    12-13 09:35:21.150: E/*****************(2875): (Perran (Bretagne))
    12-13 09:35:21.150: E/*****************(2875): (Perray (Indre-et-Loire, Centre))
    12-13 09:35:21.150: E/*****************(2875): (Perret (Côtes-d'Armor, Bretagne))
    12-13 09:35:21.150: E/*****************(2875): (Perret (Rhône-Alpes))
    12-13 09:35:21.150: E/*****************(2875): (Perrex (Ain, Rhône-Alpes))
    12-13 09:35:21.150: E/*****************(2875): (Perros (Finistère, Bretagne))
    12-13 09:35:21.150: E/*****************(2875): (Perros (Finistère, Bretagne))
    12-13 09:35:21.150: E/*****************(2875): (Perros (Bretagne))
    12-13 09:35:21.150: E/*****************(2875): (Perrou (Orne, Basse-Normandie))
    12-13 09:35:21.160: E/*****************(2875): (Perroy (Nièvre, Bourgogne))
    12-13 09:35:21.160: E/*****************(2875): (Perroy ())
    12-13 09:35:21.160: E/*****************(2875): (Perreux (Loire, Rhône-Alpes))
    12-13 09:35:21.160: E/*****************(2875): (Perreux (Yonne, Bourgogne))
    12-13 09:35:21.160: E/*****************(2875): (Perrier (Dordogne, Aquitaine))
    12-13 09:35:21.160: E/*****************(2875): (Perrier (Puy-de-Dôme, Auvergne))
    12-13 09:35:21.160: E/*****************(2875): (Perruel (Eure, Haute-Normandie))
    12-13 09:35:21.160: E/*****************(2875): (Perrelli (Corse))
    12-13 09:35:21.160: E/*****************(2875): (Perreuil (Saône-et-Loire, Bourgogne))
    12-13 09:35:21.160: I/MyActivity - received(2875): Received 20 villes from update task
    -> AFFICHAGE: Perre (inder & loire), perre (flandres) et c'est tout... alors que encore 17 autres "Perr*" derrière pourtant

    3.) je rajoute un I
    -> logcat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    12-13 09:36:10.100: D/MyActivity - filter(2875): Ville Adapter Filter changed:Perri
    12-13 09:36:10.100: D/MyActivity - starting(2875): Starting Update of Villes with Perri
    12-13 09:36:10.100: E/>>>********* ASYNC(2875): run
    12-13 09:36:10.410: E/*****************(2875): (Perrier (Dordogne, Aquitaine))
    12-13 09:36:10.410: E/*****************(2875): (Perrier (Puy-de-Dôme, Auvergne))
    12-13 09:36:10.410: E/*****************(2875): (Perrigny (Jura, Franche-Comté))
    12-13 09:36:10.410: E/*****************(2875): (Perrigny (Yonne, Bourgogne))
    12-13 09:36:10.410: E/*****************(2875): (Perrigny (Yonne, Bourgogne))
    12-13 09:36:10.410: E/*****************(2875): (Perrinet (Nièvre, Bourgogne))
    12-13 09:36:10.410: E/*****************(2875): (Perrière (PACA))
    12-13 09:36:10.410: E/*****************(2875): (Perricard (Lot-et-Garonne, Aquitaine))
    12-13 09:36:10.410: E/*****************(2875): (Perrinque (Gironde, Aquitaine))
    12-13 09:36:10.410: E/*****************(2875): (Perrières (Calvados, Basse-Normandie))
    12-13 09:36:10.410: E/*****************(2875): (Perrignier (Haute-Savoie, Rhône-Alpes))
    12-13 09:36:10.410: E/*****************(2875): (Perrigny-lès-Dijon (Côte-d'or, Bourgogne))
    12-13 09:36:10.410: E/*****************(2875): (Perrigny-sur-Loire (Saône-et-Loire, Bourgogne))
    12-13 09:36:10.410: E/*****************(2875): (Perriers-la-Campagne (Eure, Haute-Normandie))
    12-13 09:36:10.410: E/*****************(2875): (Perriers-sur-Andelle (Eure, Haute-Normandie))
    12-13 09:36:10.410: E/*****************(2875): (Perrigny-sur-l'Ognon (Côte-d'or, Bourgogne))
    12-13 09:36:10.410: E/*****************(2875): (Perriers-en-Beauficel (Manche, Basse-Normandie))
    12-13 09:36:10.410: E/*****************(2875): (Perrigny-sur-Armançon (Yonne, Bourgogne))
    12-13 09:36:10.420: I/MyActivity - received(2875): Received 18 villes from update task
    -> AFFICHAGE: Perrier (dordogne), Perrier (puy de dome) et c'est tout... alors que encore 17 autres "Perri*" derrière pourtant

    4.) je supprime le I
    -> logcat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    12-13 09:39:01.490: D/MyActivity - filter(2875): Ville Adapter Filter changed:Perr
    12-13 09:39:01.490: D/MyActivity - starting(2875): Starting Update of Villes with Perr
    12-13 09:39:01.490: E/>>>********* ASYNC(2875): run
    12-13 09:39:01.800: E/*****************(2875): (Perre (Indre-et-Loire, Centre))
    12-13 09:39:01.800: E/*****************(2875): (Perre (Flandre Orientale))
    12-13 09:39:01.800: E/*****************(2875): (Perran (Bretagne))
    12-13 09:39:01.800: E/*****************(2875): (Perray (Indre-et-Loire, Centre))
    12-13 09:39:01.800: E/*****************(2875): (Perret (Côtes-d'Armor, Bretagne))
    12-13 09:39:01.800: E/*****************(2875): (Perret (Rhône-Alpes))
    12-13 09:39:01.800: E/*****************(2875): (Perrex (Ain, Rhône-Alpes))
    12-13 09:39:01.800: E/*****************(2875): (Perros (Finistère, Bretagne))
    12-13 09:39:01.800: E/*****************(2875): (Perros (Finistère, Bretagne))
    12-13 09:39:01.800: E/*****************(2875): (Perros (Bretagne))
    12-13 09:39:01.800: E/*****************(2875): (Perrou (Orne, Basse-Normandie))
    12-13 09:39:01.800: E/*****************(2875): (Perroy (Nièvre, Bourgogne))
    12-13 09:39:01.800: E/*****************(2875): (Perroy ())
    12-13 09:39:01.800: E/*****************(2875): (Perreux (Loire, Rhône-Alpes))
    12-13 09:39:01.800: E/*****************(2875): (Perreux (Yonne, Bourgogne))
    12-13 09:39:01.800: E/*****************(2875): (Perrier (Dordogne, Aquitaine))
    12-13 09:39:01.800: E/*****************(2875): (Perrier (Puy-de-Dôme, Auvergne))
    12-13 09:39:01.800: E/*****************(2875): (Perruel (Eure, Haute-Normandie))
    12-13 09:39:01.800: E/*****************(2875): (Perrelli (Corse))
    12-13 09:39:01.800: E/*****************(2875): (Perreuil (Saône-et-Loire, Bourgogne))
    12-13 09:39:01.810: I/MyActivity - received(2875): Received 20 villes from update task
    -> AFFICHAGE: liste complète des "Perri* (et non des "Perr*"!)

    5.) je retape le I
    -> logcat
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    12-13 09:40:57.130: D/MyActivity - filter(2875): Ville Adapter Filter changed:Perri
    12-13 09:40:57.130: D/MyActivity - starting(2875): Starting Update of Villes with Perri
    12-13 09:40:57.130: E/>>>********* ASYNC(2875): run
    12-13 09:40:57.420: E/*****************(2875): (Perrier (Dordogne, Aquitaine))
    12-13 09:40:57.420: E/*****************(2875): (Perrier (Puy-de-Dôme, Auvergne))
    12-13 09:40:57.420: E/*****************(2875): (Perrigny (Jura, Franche-Comté))
    12-13 09:40:57.420: E/*****************(2875): (Perrigny (Yonne, Bourgogne))
    12-13 09:40:57.420: E/*****************(2875): (Perrigny (Yonne, Bourgogne))
    12-13 09:40:57.420: E/*****************(2875): (Perrinet (Nièvre, Bourgogne))
    12-13 09:40:57.420: E/*****************(2875): (Perrière (PACA))
    12-13 09:40:57.420: E/*****************(2875): (Perricard (Lot-et-Garonne, Aquitaine))
    12-13 09:40:57.420: E/*****************(2875): (Perrinque (Gironde, Aquitaine))
    12-13 09:40:57.420: E/*****************(2875): (Perrières (Calvados, Basse-Normandie))
    12-13 09:40:57.420: E/*****************(2875): (Perrignier (Haute-Savoie, Rhône-Alpes))
    12-13 09:40:57.420: E/*****************(2875): (Perrigny-lès-Dijon (Côte-d'or, Bourgogne))
    12-13 09:40:57.420: E/*****************(2875): (Perrigny-sur-Loire (Saône-et-Loire, Bourgogne))
    12-13 09:40:57.420: E/*****************(2875): (Perriers-la-Campagne (Eure, Haute-Normandie))
    12-13 09:40:57.420: E/*****************(2875): (Perriers-sur-Andelle (Eure, Haute-Normandie))
    12-13 09:40:57.420: E/*****************(2875): (Perrigny-sur-l'Ognon (Côte-d'or, Bourgogne))
    12-13 09:40:57.420: E/*****************(2875): (Perriers-en-Beauficel (Manche, Basse-Normandie))
    12-13 09:40:57.420: E/*****************(2875): (Perrigny-sur-Armançon (Yonne, Bourgogne))
    12-13 09:40:57.430: I/MyActivity - received(2875): Received 18 villes from update task
    -> AFFICHAGE: Perre (inder & loire), perre (flandres) et c'est tout... alors que encore 17 autres "Perri*" derrière pourtant

    Donc, oui, l'affichage semble réagir avec un temps de retard(?) par rapport aux lettres saisies.

    onVilleAdapterUpdateResult() ne semble donc pas lancé au bon moment... bien qu'il soit effectivement lancé dans le postExecute à chq remplissage Async (le logcat le prouve bien: MyActivity - received)...

    d'autant plus space qu'on vide bien la liste des data précédentes, qu'on rempli avec les nouvelles et qu'on notify le chgt du dataset(???)!

    donc là je sèche oui!
    si qq chose empêche l'effet du this.villeAdapter.notifyDataSetChanged(); je ne vosi pas quoi

    à priori (me méfie maintenant! ) ça semble qd même lié au Async, puisqu'en faisant la même chose avec un Thread ET un wait() while isAlive() l'affichage de la liste est correct, en temps réel.

  17. #17
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    à priori (me méfie maintenant! ) ça semble qd même lié au Async, puisqu'en faisant la même chose avec un Thread ET un wait() while isAlive() l'affichage de la liste est correct, en temps réel.
    Oui mais c'est interdit ....

    Maintenant je repose la question, pourquoi refaire la requête 20 fois ?
    Peut-être a tu pris la première version de mon code (et non la version corrigée après quelques tests locaux ^^ ).

    La logique:
    On tape 3 lettres (PER) => bim threshold 1 du thread => async task
    Rien n'est affiché... c'est normal.... on n'a pas encore la réponse... et surtout threshold 2 pas encore atteint.
    On tape 'I' => bim threshold 2 du textview =>
    * Si la 'task' est revenue... tant mieux, on a déjà tous les 'PER*', donc facile pour le text-view d'afficher les 'PERI*'
    * Si la 'task' n'est pas revenue.... on n'a toujours rien...
    On fait back => threshold 2 du textview non atteint => la liste devrait disparaitre (mais on n'a toujours pas relancé de tache)
    On tape 'I' => bim threshold 2 du textview ... etc....

    Si tu fais une requête sans arrêt tu auras toujours des trucs "décalés"...

    Alors maintenant, peut-être que le filtrage de l'adapter limite à 2 entrées... c'est à voir....

  18. #18
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    Citation Envoyé par nicroman Voir le message
    Oui mais c'est interdit ....
    c'est un test ... et au pire c'est pas un wait mesuré à 200ms qui va faire crasher tout ça, largement inférieur aux 5 secondes fatidiques

    Maintenant je repose la question, pourquoi refaire la requête 20 fois ?
    parce qu'on me le demande
    et aussi parce qu'il est + facile pour un user de cliquer sa ville dans la liste, que de l'obliger à taper 2, 3, 4 ou n lettres de plus pour voir apparaitre sa ville et la cliquer.

    Peut-être a tu pris la première version de mon code (et non la version corrigée après quelques tests locaux ^^ ).
    celui du 11/12/2012 15h10, d'ailleurs c'est le seul code complet que tu as posté, avant il n'y avait que la classe ville
    -> tu as fait tes tests et posté que le définitif je suppose

    La logique:
    On tape 3 lettres (PER) => bim threshold 1 du thread => async task
    Rien n'est affiché... c'est normal.... on n'a pas encore la réponse... et surtout threshold 2 pas encore atteint.
    On tape 'I' => bim threshold 2 du textview =>
    * Si la 'task' est revenue... tant mieux, on a déjà tous les 'PER*', donc facile pour le text-view d'afficher les 'PERI*'
    * Si la 'task' n'est pas revenue.... on n'a toujours rien...
    On fait back => threshold 2 du textview non atteint => la liste devrait disparaitre (mais on n'a toujours pas relancé de tache)
    On tape 'I' => bim threshold 2 du textview ... etc....
    Si tu fais une requête sans arrêt tu auras toujours des trucs "décalés"...
    mais alors comment "jouer" sur le threshold 2, pour qu'il ait la même valeur que le 1 finalement?

    parce que pour nous ce n'est pas logique justement :
    -> tu tapes 3 lettres: threshold ok ~> run du asyntack
    -> donc tu dois de suite avoir la liste des villes correspondantes
    -> et pas en décalé, à la prochaine lettre, justement, pas logique

    comment dire?

    EX1: qd tu vas au fast food tu préfères quoi?
    -> payer ta commande, aller t'asseoir pour qu'on te dise APRES qu'il n'y a plus le cheese que t'as commandé?
    OU
    -> qu'on te dise de suite "désolé, plus de cheese", tu choisis & payes autre chose et tu vas t'asseoir tranquilou pour manger?

    EX2: pour composer un n° de téléphone, trouverais-tu normal d'être obligé de taper un 11èm chiffre, bidon, pour lancer la numérotation parce que celle-ci ne démarre pas après la saisie du 10èm et dernier chiffre du numéro?

    ou alors on croit qu'on parle de la même chose alors que ce n'est pas du tout le cas?


    Alors maintenant, peut-être que le filtrage de l'adapter limite à 2 entrées... c'est à voir....
    je regarde ça

  19. #19
    Expert confirmé

    Homme Profil pro
    Ingénieur systèmes et réseaux
    Inscrit en
    Février 2007
    Messages
    4 253
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Ingénieur systèmes et réseaux
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Février 2007
    Messages : 4 253
    Billets dans le blog
    3
    Par défaut
    largement inférieur aux 5 secondes fatidiques
    Sur certains téléphones (le miens par exemple) c'est largement moins que 5 secondes ^^

    parce qu'on me le demande
    On te demande de faire un appel au webservice à chaque caractère ?

    parce que pour nous ce n'est pas logique justement :
    -> tu tapes 3 lettres: threshold ok ~> run du asyntack
    -> donc tu dois de suite avoir la liste des villes correspondantes
    Non c'est impossible.... de part l'utilisation d'un webservice...
    Le webservice peut ne pas répondre, répondre en 30s, comme répondre en 60ms...
    Pour éviter les ANR, il faut passer par une tâche asynchrone....
    Maintenant... comment rendre cette tâche asynchrone imperceptible dans 99% des cas... en l’exécutant *avant* que les données soient réellement utiles.

    Dans mon code (modifié le 11/12/2012 à 17h10) il y a deux threshold:
    un THRESHOLD_TASK, qui permet de définir à partir de combien de caractères on doit démarrer la tâche de récupération des villes (complètement invisible à l'utilisateur dans tous les cas).
    et un THRESHOLD_DROPDOWN, qui permet de définir à partir de combien de caractères on doit afficher le dropdown (le seul threshold visible pour l'utilisateur).
    Plus l'écart entre les deux est grand, plus on a de temps pour récupérer la liste.
    Plus le THRESHOLD_TASK est bas, plus on aura de réponses du webservice (et donc de la mémoire utilisée, et du ralentissement à l'utilisation du dropdown).
    Plus le THRESHOLD_DROPDOWN est élevé, moins l'utilisateur aura le choix rapidement...

    L'idée est que le temps qu'on ai atteint THRESHOLD_DROPDOWN caractères on aura eu le temps de récupérer les villes qui correspondent.

    Ensuite, on ne refait *jamais* la requete, tant qu'on est pas descendu en dessous de THRESHOLD_TASK (pas la peine, c'est toujours les même caractères, donc toujours la même liste de ville).

    Mettre les deux thresholds à la même valeur peut être une solution, mais qui verra le dropdown "ramer" (rien d'affiché pendant un certain moment) si le réseau rame....

    En me relisant, je me demande si tu fais la différence entre:
    (a) La liste des villes dans l'adapter.
    (b) La liste des villes affichées par l'autocomplete...

    (a) est invisible pour l'utilisateur
    (b) est selectionné par l'autocomplete text-view à partir des données de l'adapter... (filtres)

    Donc tu peux avoir un adapter avec "PERRET, PERRIN, PERTUIS" et un drop down avec seulement "PERTUIS" parceque tu as tapé "PERT"

  20. #20
    Membre éclairé
    Homme Profil pro
    Inscrit en
    Mai 2012
    Messages
    535
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Mai 2012
    Messages : 535
    Par défaut
    Dans mon code (modifié le 11/12/2012 à 17h10) il y a deux threshold:
    ok, compris le problème: il n'y a pas de mention de mise à jour (Dernière modification par xxxxx ; 11/12/2012 à xxhxx. ) de ce post!
    -> donc pour moi il n'avait pas changé! pas retourné voir du coup!
    -> je bosse donc bien sur "l'ancienne version" depuis le début!!! grrrrrrrrrrrr!!!

    En me relisant, je me demande si tu fais la différence entre:
    (a) La liste des villes dans l'adapter.
    (b) La liste des villes affichées par l'autocomplete...
    heu, non, pour moi c'était bien la même chose... voilà le problème de compréhension!
    -> c'est space (à mes yeux) de différencier les 2...

    bon faut que je relise calmement toute ta réponse...

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo