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 :

Comment lancer une application autonome en arrière-plan ?


Sujet :

Android

  1. #1
    Membre régulier Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 83
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité d'Eurocopter
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 69
    Points : 72
    Points
    72
    Par défaut Comment lancer une application autonome en arrière-plan ?
    Bonjour à tous,

    Désolé, je n'ai pas réussi à trouver une discussion qui puisse répondre à mon problème. Si besoin, pourrais-je connaître l'endroit approprié pour ce post ?

    J'ai écrit une petite application GPS qui collecte en continu les géolocalisations d'un parcours. Aucun problème pour la réaliser. Elle fonctionne à peu près correctement. Je ne m'étendrais donc pas sur cet aspect.

    Seulement, voilà... à l'usage, cette application est inexploitable.

    J'essaie donc d'expliquer pourquoi ?

    Collecter les géolocalisations d'un parcours peut durer un temps suffisamment important (15, 30 minutes, voir une ou plusieurs heures) durant lequel on peut être amené à passer ou recevoir une communication téléphonique, envoyer un SMS, bref, exécuter une autre application. Dans ces cas de figure, l'application GPS est tuée par Android conformément à ce qui est écrit dans la doc et éventuellement relancée s'il y a rotation d'écran. Pendant le laps de temps qui sépare l'arrêt de la reprise, la collecte est interrompue provoquant alors un trou dans la trajectoire. Ceci est donc inacceptable.

    Question générale :

    Comment une application peut-elle lancer en arrière-plan une autre application qui puisse continuer à travailler imperturbablement en parallèle avec d'autres applications ?

    Ce que j'ai essayé sans succès :

    Ce type d'application est fort simple à découper. Il se réduit à 2 composants complètement indépendants :
    1. L'activité principale se contente simplement d'afficher des informations de géolocalisation qu'elle peut puiser dans un conteneur par exemple. Cette application, en relation avec l'utilisateur, peut très bien être interrompue n'importe quand, ce n'est pas gênant, elle peut être relancée à tout moment.
    2. l'activité-fille collecte les géolocalisations sans interruption tant qu'une commande ne lui demande pas de s'arrêter.

    Ceci sous entend 2 problèmes :
    1. L'application-fille (2) d'arrière plan ne fait que calculer des informations qui doivent être affichées par l'activité (1). Il faut donc une communication ASYNCHRONE avec l'activité (1) qui, fonctionnellement est autonome.
    2. L'activité (1) prépare les conditions de la géolocalisation, lance l'activité (2) et va chercher à intervalles réguliers les informations déposées de la géolocalisation qu'elle affiche.


    Pour lancer l'application (2) du GPS, j'ai utilisé la séquence que l'on trouve maintes fois sur la Toile :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
        ....
        try
        {
          Intent intention = getPackageManager().getLaunchIntentForPackage("com.example.tachygps");
          if (intention == null)
            throw new PackageManager.NameNotFoundException() ;
                intention.addCategory(Intent.CATEGORY_LAUNCHER);
                startActivity(intention);
        }
        catch (PackageManager.NameNotFoundException e)
        {
          System.out.println("  !!!  " + "Application non présente sur le téléphone...") ;
        }
        ....
    Elle marche parfaitement bien. L'activité (2) réagit à l'Emulator Control.

    Questions complémentaires :

    A - Comment coder l'application (2) pour qu'elle n'affiche pas ce layout blanc malgré la suppression :

    • de la carte « setContentView(R.layout.tachy_gps) ; »
    • du fichier layout « res/layout/tachy_gps.xml »

    ce qui a le fâcheux inconvénient de la tuer pour lancer une autre application.

    B - Quel est l'outil le mieux adapté pour assurer la communication ASYNCHRONE entre les deux applications en gérant un conteneur ?
    Utiliser un simple fichier me paraît assez limite pour la partageabilité. J'avais pensé aux 'Shared Preferences" en "MODE_MULTI_PROCESS", je n'ai pas réussi à les faire marcher !...
    .

    Auriez-vous une autre méthode pour résoudre le problème ?

    En vous remerciant par avance pour vos éclairages.

    Lou Papet

  2. #2
    Modérateur
    Avatar de grunk
    Homme Profil pro
    Lead dév - Architecte
    Inscrit en
    Août 2003
    Messages
    6 691
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France, Côte d'Or (Bourgogne)

    Informations professionnelles :
    Activité : Lead dév - Architecte
    Secteur : Industrie

    Informations forums :
    Inscription : Août 2003
    Messages : 6 691
    Points : 20 230
    Points
    20 230
    Par défaut
    Tu dois utiliser un service pour faire ce que tu veux faire , pas une activity

  3. #3
    Membre régulier Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 83
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité d'Eurocopter
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 69
    Points : 72
    Points
    72
    Par défaut à grunk
    Bonsoir,

    Pour bien vous dire, j'avais effectivement lu la page sur les services que vous m'avez citée dans votre message.

    En y réfléchissant bien, je devine un peu dans la brume androidienne ce que l'on peut faire. Mais, novice, je ne vois toujours pas comment on peut lancer concrètement une tâche qui reste résidente et active alors que l'activité maîtresse qui l'a lancée peut très bien se terminer donc, complètement disparaitre. J'avoue que l'exemple qui est fourni m'est apparu, à moi bien sûr, bien ténébreux, tortueux et noyé dans de l'enrobage. Je n'ai pas réussi à le transcrire dans mon appli.

    Le problème est pourtant diaboliquement simple :
    1. Soit une tâche, un programme, une activité, comme vous voulez, nommée "p1",
    2. Soit une tâche, un programme, une activité, comme vous voulez, nommée "p2",

    Comment coder dans "p1" le lancement de "p2" dans un autre process pour que "p1" puisse se terminer et disparaître alors que "p2" continue sa vie ?

    Par exemple, en C sous Linus, Unix Sys V et Bsd 4.2, il suffit de coder dans "p1" une instruction ci-dessous pour faire le travail ultra simplement :

    system("p2 parm1 parm2 .... ... &) ;

    (le "&" est important pour indiquer un processus différent
    et retour immédiat à l'appel)

    (Avec les fonctions "execl" du C, le process-fils "p2" REMPLACE le processus-père "p1", ce que je ne correspond pas à l'objectif).

    Personnellement, je n'en demanderais pas plus.

    Serait-il possible d'avoir
    - soit un exemple sans enrobage pour bien isoler l'usage du service,
    - soit avoir un lien vers un exemple exécutable ?

    D'avance merci.

    Lou Papet

  4. #4
    Expert éminent

    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
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Mais pourquoi vouloir un autre process ?

    Il y a un process: l'application.
    Chaque process peut avoir plusieurs threads (libre au système d'en décider).
    Il est même possible de forcer une application à avoir le même process qu'une autre application.

    Une application n'est qu'un gros sac, dans lequel on met des activités (les vrais "programmes" au sens desktop), et des services (les "services" au sens windows ).

    Toutes les activités d'une application peuvent bien avoir quitté, si le service ne dit pas "j'ai fini", il tournera...

  5. #5
    Membre régulier Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 83
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité d'Eurocopter
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 69
    Points : 72
    Points
    72
    Par défaut
    À grunk pour information
    Tu dois utiliser un service pour faire ce que tu veux faire , pas une activity
    À force de chercher, j'ai fini par trouver un tuto bien plus clair que celui que vous m'avez cité, plus fait pour les gens expérimentés qui maîtrisent déjà la logique. Il s'agit de la page ICI dans laquelle il y a un exemple qui marche mais qui, sans être très démonstratif, m'a bien fait progressé.

    Je l'ai donc adapté sur une petite maquette ci-après qui est sensée fonctionner comme mon application GPS.

    À nicroman
    Mais pourquoi vouloir un autre process ?
    Je ne suis pas particulièrement attaché au process. Je souhaite simplement que cela fonctionne comme je le souhaite, à savoir, téléphoner durant une activité de longue géolocalisation sans l'interrompre.

    À partir de l'exemple donné dans le tuto cité, voici donc cette petite maquette que je souhaiterais voir fonctionner sur le même principe que celui de mon application GPS.

    Malheureusement, je n'arrive pas pas à la faire marcher correctement.

    I - L'activité (1) : elle doit pouvoir être arrêtée ou tuée :
    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
    /***************************************************************************************************
           L'application est une maquette permettant de  tester le lancement d'une activité (2) qui
       continue à travailler malgré l'arrêt de l'activité (1) qui l'a lancée.
       
           Ce test s'inspire de l'exemple pas très démonstratif (!!!) donné dans la page
           
                      "http://www.tutorialspoint.com/android/android_services.htm"
            
    ***************************************************************************************************/
    package loupapet.test;
     
    import java.util.Calendar;
     
    import android.app.Activity;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences ;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.View;
     
    /***************************************************************************************************
                                             L'activité (1) 
    ***************************************************************************************************/
    public class Activite1 extends Activity
    {
     
      @Override
      protected void onCreate(Bundle savedInstanceState)
      {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activite_1);
     
      //*** On prend la date du moment du lancement du service uniquement pour permettre d'identifier
      //    que l'activité (2) s'exécute bien même si la présente activité (1) est arrêtée :
        Calendar cal          = Calendar.getInstance() ;
     
        int annee             = cal.get(Calendar.YEAR) ;
        int mois              = cal.get(Calendar.MONTH) + 1 ;
        int jour              = cal.get(Calendar.DAY_OF_MONTH) ;
        int heures            = cal.get(Calendar.HOUR_OF_DAY) ;
        int minutes           = cal.get(Calendar.MINUTE) ;
        int secondes          = cal.get(Calendar.SECOND) ;
        int dixiemes          = cal.get(Calendar.MILLISECOND)/100 ;
     
        String date = String.format( "%04d-%02d-%02d %02d:%02d:%02d.%1d"
                                   , annee , mois   , jour
                                   , heures, minutes,secondes, dixiemes) ;
     
        System.out.println( "Activité (1) : " + "Identificateur : " + date ) ;
     
      //*** On envoie cet identificateur dans les 'Shared Preferences" :
      //      1 - pour que l'activité (2) le récupère afin de tester la communication entre
      //          les deux activités (1) et (2),
      //      2 - pour que l'activité (2) montre clairement qu'elle s'exécute en continu en
      //          l'affichant dans la CatLog toutes les 5 secondes.
        SharedPreferences settings = getSharedPreferences("mes_preferences", Context.MODE_MULTI_PROCESS);
        settings.edit().putString("date", date).commit();
      }
     
    //*** On crée un menu à 3 boutons :
      @Override
      public boolean onCreateOptionsMenu(Menu menu)
      {
        getMenuInflater().inflate(R.menu.activite1, menu);
        return true;
      }
     
    //*** La méthode démarre le service : Elle lance donc l'activité (2) :
      public void startService(View view)
      {
        System.out.println ("Activité (1) : " + "lancement du service") ;
        startService(new Intent(getBaseContext(), Activite2.class));
      }
     
    //*** La méthode met fin au service et par voie de conséquence à l'activité (2) :
      public void stopService(View view)
      {
        System.out.println ("Activité (1) : " + "arrêt du service") ;
        stopService(new Intent(getBaseContext(), Activite2.class));
      }
     
    //*** La méthode permet de sortir de l'activité (1) sans arrêter le service :
    //    L'activité (2) doit normalement continuer sa vie.
      public void sortie(View view)
      {
        System.out.println ("Activité (1) : " + "Sortie du l\'activité") ;
        finish() ;
      }
    }
    II - Le fichier AndroidManifest.xml :
    C'est le fichier standard de "HelloWord" avec une ligne ajoutée spécifiant le service :

    <service android:name=".Activite2" />

    III - le layout "activite1.xml" : il définit 3 boutons, un bouton "Sortie avec service actif" de plus que celui du test proposé :
    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
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       android:orientation="vertical" >
     
       <Button android:id="@+id/btnStartService"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:text="Démarrage du service"
       android:onClick="startService"/>
     
       <Button android:id="@+id/btnStopService"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:text="Arrêt du service"
       android:onClick="stopService" />
     
       <Button android:id="@+id/btnSortie"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:text="Sortie avec service actif"
       android:onClick="sortie" />
     
    </LinearLayout>
    IV - L'activité (2) : Elle doit fonctionner continument tant qu'on n'impose pas son arrêt.
    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
    /***************************************************************************************************
                      "Acticite2" : C'est le deuxième composant de la maquette
     
            L'activité récupère l'identificateur fourni par l'activité (1) et l'affiche toutes les
       5 secondes pour montrer qu'elle est active même si l'activité (1) qui l'a lancée a été arrêtée
       ou a été détruite.
    ***************************************************************************************************/
    package loupapet.test ;
     
    import java.util.Calendar;
     
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences ;
    import android.os.IBinder;
    import android.widget.Toast;
     
    /***************************************************************************************************
                                             L'activité (2) 
    ***************************************************************************************************/
    public class Activite2 extends Service 
    {
       private String date ;
     
       @Override
       public IBinder onBind(Intent arg0) 
       {
         System.out.println( "Activité (2) : " + "Entrée dans l\'activité (onBind)") ;
         return null;
       }
     
    //*** Exécution de l'activité (2) en continu
       @Override
       public int onStartCommand(Intent intent, int flags, int startId) 
       {
     
         new Thread().start() ;
     
         System.out.println( "Activité (2) : " + "le service démarré => exécution en continu") ;
     
       //*** On récupère des "Shared Preferences" l'identifoicateur initialisé par l'activité (1) 
        SharedPreferences settings = getSharedPreferences("mes_preferences", Context.MODE_MULTI_PROCESS);
        String date = settings.getString("date", "") ;
     
         for(int i = 0 ; i < 500 ; i++)
         { try
           { Thread.sleep(5000) ;
             System.out.println( "Activité (2) : " + "Service en cours :\n"
                               + "               " + "i = " + i + " - " + date ) ;
           }
           catch (InterruptedException e)
           { e.printStackTrace() ; 
             System.out.println( "Activité (2) : " + "Erreur Thread sleep :\n" + e.getMessage() ) ;
           }
         }
     
       //*** Grâce à "StART_STICKY" L'activité (2) continue de travailler :
         return START_STICKY;
       }
     
       @Override
       public void onDestroy() 
       {
          super.onDestroy() ;
     
          System.out.println( "Activité (2) : " + "Service terminé => activité arrêtée" ) ;
       }
    }
    Alors, que se passe-t-il ?

    1. Quand on clique sur le bouton "Sortie avec service actif", l'application se termine normalement, le bouton que j'ai ajouté marche,
    2. Quand on clique sur le bouton "Démarrage du service", on voit dans la LogCat
      • que l'activité (1) lance bien le service,
      • que l'activité (2) s'exécute en affichant toutes les 5 secondes l'identificateur créé dans l'activité (1),
      • au bout d'une vingtaine de secondes, 5 à 6 itérations de l'activité (2), le système affiche un panneau indiquant :

        L'application Activite1 ne répond pas?
        Voulez-vous la fermer ?
      • L'activité (2) continue toujours à afficher l'identificateur
    3. Pendant que l'activité (2) tourne, les boutons "Arrêt du service" et "Sortie avec service actif" sont inopérants,
    4. au bout d'une vingtaine de secondes, le système affiche le panneau ci-dessus cité.

      J'ai bien soupçonné l'instruction " return START_STICKY" dans l'activité (2) mais cela n'a pas l'air d'être cela.

      Avez-vous une idée expérimentée ?

      Encore merci d'avance.

      Lou Papet

  6. #6
    Expert éminent

    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
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Oui forcément....

    L'Activity1 (qui est bien une "Activity") appelle startService.
    Ce que va démarrer le service:
    L'Activity2 (qui devrait s'appeler "Service" à priori) on StartCommand est appelé
    *mais on ne revient jamais*
    Du coup on ne revient jamais du "startService" de l'Activity1 qui du coup va être flagué par le système comme "not-responsive".

    D'ailleurs new Thread().start(); ne sert à rien ... cela va démarrer un thread vide (sans code).


    Je pense qu'il manque un onCreate() dans le service (début de l'écoute de la localisation), un onDestroy() (arrêt de l'écoute).
    le onStartCommand ne faisant rien du tout... (sauf à renvoyer STICKY sans doute).

    A noter que le "listener" de localisation va recevoir les évenements de localisation sans qu'il soit besoin de créer un thread !



    Quant à:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    Calendar cal          = Calendar.getInstance() ;
     
        int annee             = cal.get(Calendar.YEAR) ;
        int mois              = cal.get(Calendar.MONTH) + 1 ;
        int jour              = cal.get(Calendar.DAY_OF_MONTH) ;
        int heures            = cal.get(Calendar.HOUR_OF_DAY) ;
        int minutes           = cal.get(Calendar.MINUTE) ;
        int secondes          = cal.get(Calendar.SECOND) ;
        int dixiemes          = cal.get(Calendar.MILLISECOND)/100 ;
     
        String date = String.format( "%04d-%02d-%02d %02d:%02d:%02d.%1d"
                                   , annee , mois   , jour
                                   , heures, minutes,secondes, dixiemes) ;
    Il vaut quand même mieux utiliser:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
    String date = sdf.format(new Date());

  7. #7
    Membre régulier Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 83
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité d'Eurocopter
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 69
    Points : 72
    Points
    72
    Par défaut À nicroman
    Bonjour,

    Bien merci pour votre réponse. Je vais essayer de décrire le "résultat des courses" !...

    En effet, l'instruction "new Thread().start() ;" est inutile, je l'ai supprimée et les suspensions de 5 secondes marchent comme avant.

    La méthode onDestroy() existait déjà. Comme vous me l'avez suggéré, j'ai ajoutée une méthode onCreate() dans laquelle je ne sais pas ce qu'il faut y mettre. À l'exécution, on y rentre bien.

    La méthode "onStartCommand(Intent intent, int flags, int startId)" fait quelque chose en réalité puisqu'elle simule un traitement long par 500 suspensions de 5 secondes.

    Voici le source modifié :

    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
    /***************************************************************************************************
                      "Acticite2" : C'est le deuxième composant de la maquette
     
            L'activité récupère l'identificateur fourni par l'activité (1) et l'affiche toutes les
       5 secondes pour montrer qu'elle est active même su l'activité (1) qui l' lancée s'est arrêtée
       ou a été détruite.
    ***************************************************************************************************/
    package loupapet.test ;
     
    import java.util.Calendar;
     
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences ;
    import android.os.IBinder;
    import android.widget.Toast;
     
    /***************************************************************************************************
                                             L'activité (2) 
    ***************************************************************************************************/
    public class Activite2 extends Service 
    {
       private String date ;
     
       @Override
       public void onCreate() 
       {
          super.onCreate() ;
     
          System.out.println( "Activité (2) : " + "Service créé" ) ;
       }
     
       @Override
       public IBinder onBind(Intent arg0) 
       {
         System.out.println( "Activité (2) : " + "Service lié => (onBind)") ;
         return null;
       }
     
    //*** Exécution de l'activité (2) en continu
       @Override
       public int onStartCommand(Intent intent, int flags, int startId) 
       {
     
    //   new Thread().start() ;
     
         System.out.println( "Activité (2) : " + "le service démarré => exécution en continu") ;
     
       //*** On récupère des "Shared Preferences" l'identifoicateur initialisé par l'activité (1) 
        SharedPreferences settings = getSharedPreferences("mes_preferences", Context.MODE_MULTI_PROCESS);
        String date = settings.getString("date", "") ;
     
         for(int i = 0 ; i < 500 ; i++)
         { try
           { Thread.sleep(5000) ;
             System.out.println( "Activité (2) : " + "Service en cours :\n"
                               + "               " + "i = " + i + " - " + date ) ;
           }
           catch (InterruptedException e)
           { e.printStackTrace() ; 
             System.out.println( "Activité (2) : " + "Erreur Thread sleep :\n" + e.getMessage() ) ;
           }
         }
     
       //*** Grâce à "StART_STICKY" L'activité (2) continue de travailler :
         return START_STICKY;
       }
     
       @Override
       public void onDestroy() 
       {
          super.onDestroy() ;
     
          System.out.println( "Activité (2) : " + "Service terminé => activité arrêtée" ) ;
       }
    }
    À l'exécution, rien n'est changé, j'ai toujours le message du système indiquant que "L'application Activité1 ne répond pas". et les deux boutons "Arrêt du service" et "Sortie avec service actif" inopérants.

    Par contre, j'ai essayé quelque chose qui pourrait être un peu plus intéressant, qui fait fonction du bouton "Sortie avec service actif", que je n'ai pas testé avant et qui pourrait peut-être vous mettre sur une voie :

    Avant que le message système s'affiche, j'ai forcé la sortie de l'activité (1) en passant par le "Home" du système pour accéder à la page des applications. Cela devrait être la procédure normale.

    Le service continue de tourner pendant que je lance d'autres applications comme "Paramètres" par exemple ou même ma première application GPS, mais il se trouve apparemment extrêmement ralenti pendant tout le temps de l'exécution de l'activité externe comme s'il avait une priorité beaucoup plus basse ou comme si le multitâche ne fonctionnait pas au top pour lui.
    Si je relance l'activité (1), les 3 boutons s'affichent normalement, le service continue de travailler et le message système NE s'affiche PLUS TANT QUE je ne touche pas le bouton "Arrêt du service" qui reste toujours inopérant.
    Pendant tout le temps des tests, le service a tourné sur plus de 200 suspensions de 5 secondes. Si je réponds "Attendre" au message et que je laisse aller le service se terminer de lui-même au bout de 500 suspensions, l'activité (1) redémarre.

    J'ai quand même l'impression d'avancer, je constate que là, cela fonctionne presque comme je le souhaite mais je ne vois pas comment fiabiliser l'ensemble : plus de message et des boutons opérants.

    Ma description des phénomènes est-elle bonne et claire ? Pardon pour la longueur de ma réponse, mais retraité de 73 ans, je suis tout seul dans mon coin et n'ai pas l'occasion, comme pendant mon activité, d'exposer de vive voix ce qu'il se passe ou de faire des stages. Donc autoformation à bloc !...

    Je souhaiterais que cette petite maquette ne soit pas dépendante de telle ou telle fonctionnalité comme le GPS par exemple car je vois d'autres applications qui n'implique pas le GPS.

    Enfin pour terminer, merci de votre conseil d'utiliser "SimpleDateFormat()" que je connais. Remarques, critiques, conseils, suggestions, etc... tout est bon à prendre. Mais à l'analyse, on choisit de suivre ou non. Vous avez raison, c'est plus simple à écrire mais en réalité, derrière cette fonction, il y a exactement ce que j'ai écrit augmenté de tous les traitements qui permettent de choisir un format donné, que l'on "trimbale" pour rien, à l'exécution et en place mémoire dès que l'on en a choisi un. Comme j'essaie de privilégier, tant que faire se peut, l'exécution à la facilité d'écriture (je suis d'une vieille école !..), je préfère donc continuer à utiliser cette méthode qui paraît un peu triviale.

    En vous remerciant encore sincèrement de vos éclairages.
    Cordialement.

    Lou Papet

  8. #8
    Expert éminent

    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
    Points : 7 618
    Points
    7 618
    Billets dans le blog
    3
    Par défaut
    Il y a 3 problèmes majeurs, je vais essayer de synthétiser le truc:


    Vous faites une simulation qui ne correspond pas à ce qu'il va se passer à la fin.

    onStartCommand est une fonction "UI" (par cela j'entends "main-thread") ce qui veut dire qu'elle *doit* se terminer aussi vite que possible (ce qui n'est pas le cas actuellement, d'ou l'ANR affiché.

    Ce que vous faites:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    ACTIVITY.onClick() (main-thread)
       startService()
        =>  SERVICE.onCreate()
        =>  SERVICE.onStartCommand()
             => sleep(...);  (on sait ce que je pense de "sleep();" :D )
             => SERVICE.recordLocation();
             => sleep(...);
             => SERVICE.recordLocation();
                 ...
    => ANR (puisque qu'on ne revient jamais du onClick !)
    Ce qui va se passer quand tout sera implémenté:
    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
     
    ACTIVITY.onClick (main-thread)
        startService()
         => SERVICE.onCreate()
                  LOCMANAGER.startListeningLocation(onLocationUpdate)
         => SERVICE.onStartCommand()
                   pas grand chose :)
     
    LOCATION-EVENT (envoyé par le location-manager suite au start location listening du onCreate)
       => SERVICE.onLocationUpdate()
       => SERVICE.recordLocation();
     
    ACTIVITY.onClick() (main-thread)
        stopService()
          => SERVICE.onDestroy()
                  LOCMANAGER.stopListeningLocation(onLocationUpdate du service)
    Comme on le voit à aucun moment il n'y aura de code bloquant, ni même besoin de thread séparé !

    Maintenant, si vous voulez tester *sans* le location-manager, c'est possible...
    Mais pour le coup, la génération des événements *devra* être dans un thread à part, et passer par les Handler (pour bien récupérer les évenements dans le "main-thread" du process).
    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
     
    SERVICE.onCreate()
        myHandler = new Handler(onLocationUpdate);
        myThread = new Thread(new Runnable() {
            while (1) { 
              sleep(500);
              myHandler.sendMessage(...);
            }
         }
     
    SERVICE.onLocationUpdate()
        .. voir plus haut
     
    SERVICE.onDestroy()
         myThread.stop();
    Attention... pseudo code ! A prendre avec des pincettes donc !

  9. #9
    Membre régulier Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 83
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité d'Eurocopter
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 69
    Points : 72
    Points
    72
    Par défaut À nicroman
    Rebonjour,

    Merci pour votre prompte réponse.

    J'ai essayé d'intégrer le processus de fonctionnement intégralement basé sur l'évènementiel.

    Je commence peut-être à percevoir ce qu'il faut faire, je vais donc essayer de suivre ce que vous m'avez exposé.

    Je n'abuserai donc pas davantage de votre temps, je resterai silencieux pendant l'adaptation de mon programme et, si vous le permettez, je reviendrais sur le forum un peu plus tard pour vous faire part de l'avancement.
    Je crois que cela devient très intéressant.

    Je ne marque donc pas le post comme résolu.

    Encore Merci.
    Cordialement.

    Lou Papet

  10. #10
    Membre régulier Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 83
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité d'Eurocopter
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 69
    Points : 72
    Points
    72
    Par défaut À nicroman
    Bonjour,

    Merci beaucoup pour vos conseils. Je reviens plus tôt sur le forum car je pensais patauger davantage.

    J'ai donc adapté votre synoptique pour donner ce qui suit et qui marche absolument conformément à ce que je souhaitais.

    Je joins à tout hasard les codes :

    I - L'application "Activit1" qui peut disparaître sans problème pendant que le service l'activité (2) continue de tourner :
    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
    /***************************************************************************************************
           L'application est une maquette permettant de  tester le lancement d'une activité (2) qui
       continue à travailler malgré l'arrêt de l'activité (1) qui l'a lancée.
    ***************************************************************************************************/
    package loupapet.test;
     
    import java.util.Calendar;
     
    import android.app.Activity;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences ;
    import android.os.Bundle;
    import android.view.Menu;
    import android.view.View;
     
    /***************************************************************************************************
                                             L'activité (1) 
    ***************************************************************************************************/
    public class Activite1 extends Activity
    {
     
      @Override
      protected void onCreate(Bundle savedInstanceState)
      {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activite_1);
     
        System.out.println( "Activité (1) : démarrée" ) ;
      }
     
    //*** On crée un menu à 3 boutons :
      @Override
      public boolean onCreateOptionsMenu(Menu menu)
      {
        getMenuInflater().inflate(R.menu.activite1, menu);
        return true;
      }
     
    //*** La méthode démarre le service : Elle lance donc l'activité (2) :
      public void startService(View view)
      {
        System.out.println ("Activité (1) : " + "lancement du service") ;
        startService(new Intent(getBaseContext(), Activite2.class));
      }
     
    //*** La méthode met fin au service et par voie de conséquence à l'activité (2) :
      public void stopService(View view)
      {
        System.out.println ("Activité (1) : " + "arrêt du service") ;
        stopService(new Intent(getBaseContext(), Activite2.class));
      }
    }
    II - Le service "Activite2" qui fait sa vie :
    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
    /***************************************************************************************************
           La présente activité (2) est en réalité un service qui permet d'effectuer des captures de
       géolocalisations en arrière plan tant que l'application (1) ne lui a pas donné l'ordre de
       s'arrêter.
    ***************************************************************************************************/
    package loupapet.test;
     
    import android.app.Activity;
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences;
    import android.location.*;
    import android.os.* ;
    import android.os.Bundle;
    import android.os.IBinder;
     
    import java.io.*;
    import java.lang.Math;
    import java.util.*;
     
    /***************************************************************************************************
                                             L'activité (2) 
    ***************************************************************************************************/
    public class Activite2 extends Service
    {
      private LocationManager lm = null  ;
      private double          latitude   ;
      private double          longitude  ;
      private double          altitude   ;
      private float           precision  ;
     
    //=================================================================================================
    //                            *** Les méthodes de contrôle du service ***
    //=================================================================================================
      @Override
      public IBinder onBind(Intent arg0)                                      // Attachement du service
      {
        System.out.println( "Activité (2) : " + "Service attaché (onBind)") ;
        return null;
      }
     
      @Override
      public int onStartCommand(Intent intent, int flags, int startId)          // Démarrage du service
      {
        System.out.println ("Activité (2) : " + "Service démarré (onStartCommand)") ;
        return START_STICKY ;     // Le service continue même si l'activité qui l'a lancée est détruite
      }
     
      @Override
      public void onDestroy()                                                 // destruction du service
      { System.out.println ("Activité (2) : " + "détruite (onDestroy)") ;
        if(lm != null)
        { lm.removeUpdates(ll) ;
          System.out.println ("               " + "mises à jour supprimées") ;
        }
        lm = null;
      }
     
      @Override
      public void onRebind(Intent intent)                                   // reattachement du service
      {
        System.out.println ("Activité (2) : " + "réattachée (onRebind)") ;
      }
     
      public void onCreate()                                                     // Création du service
      {
        System.out.println ("Activité (2) : " + "Service créé (onCreate)") ;
     
      //*** Lancemant de la géolocalisation :
        lm = (LocationManager) this.getSystemService(LOCATION_SERVICE) ;
     
        if(lm != null)                                                       // pour propreté au cas où
        { lm.removeUpdates(ll) ;
          System.out.println ("               " + "mises à jour supprimées") ;
        }
        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, ll) ;
      }
     
    //=================================================================================================
    //                     *** Les méthodes de traitement de la géolocalisation ***
    //=================================================================================================
      private LocationListener ll = new LocationListener()
      {
        public void onLocationChanged(Location geoloc)
        {
          latitude  = geoloc.getLatitude() ;
          longitude = geoloc.getLongitude() ;
          altitude  = geoloc.getAltitude() ;
          precision = geoloc.getAccuracy() ;
     
          System.out.println ( "Activité (2) :\n"
                             + "         - longitude=" + longitude + "\n"
                             + "         - latitude="  + latitude  + "\n"
                             + "         - altitude="  + altitude  + "\n"
                             + "         - précision=" + precision
                             )  ;
        }
     
        public void onProviderEnabled(String provider)
        {
          System.out.println ( "Activité (2) :\n"
                             + "         - " + provider + " est maintenant actif (Enabled)" 
                             ) ;
        }
     
        public void onProviderDisabled(String provider)
        {
          System.out.println ( "Activité (2) :\n"
                             + "         - " + provider + " est maintenant inactif (Disabled)" 
                             ) ;
        }
     
        public void onStatusChanged(String provider, int statut, Bundle extras)
        {
          String etat = "" ;
     
          switch (statut)
          { case LocationProvider.OUT_OF_SERVICE          : etat = "HORS_SERVICE"            ; break ;
            case LocationProvider.TEMPORARILY_UNAVAILABLE : etat = "TEMPORAIREMENT_INVALIDE" ; break ;
            case LocationProvider.AVAILABLE               : etat = "VALIDE"                  ; break;
          }
          System.out.println ( "Activité (2) :\n"
                             + "         - " + provider + " a maintenant le status " + etat ) ;
        }
      } ;
    }
    Je pressens cependant un petit problème pour mon application GPS. Dans la version non satisfaisante, la mise à jour des géolocalisations était un évènement qui me permettait d'afficher automatiquement sans intervention (toucher de l'écran) les paramètres du parcours.
    Dans cette approche, je ne dispose plus de cet évènement. Je vais continuer à étudier le problème du côté des timers, c'est peut-être la solution, car j'imagine qu'il est possible de poster des tops d'horloge pour exécuter cycliquement ma routine d'affichage et que le sleep que vous n'aimez pas est en effet inapproprié car, dans la logique de son utilisation, il ne permet pas dans l'UITread de redonner la main à Android dans les 5 secondes.

    Maintenant à moi de jouer.
    Cordialement.

    Lou Papet

  11. #11
    Membre régulier Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 83
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité d'Eurocopter
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Janvier 2009
    Messages : 69
    Points : 72
    Points
    72
    Par défaut À nicroman
    Bonsoir,

    Je viens donc de passer quelque temps sur la documentation concernant les timers. Je suis tombé sur quelques posts qui déconseillaient d'utiliser la 'public abstract class TimerTask' au profit de la 'public class Handler'. J'ai donc suivi l'information sans avoir expérimenté.

    Résultat : la maquette marche nickel comme je le souhaitais. Je dépose donc les fichiers de l'application s'ils peuvent servir à des débutants comme moi avec prudence quand même. Je suis à l'écoute d'anomalies éventuelles.

    I - L'application nommée 'activite1' :
    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
    /***************************************************************************************************
           L'application est une maquette permettant de  tester le lancement d'une activité (2) (GPS)
       qui continue à travailler malgré l'arrêt de l'activité (1) qui l'a lancée. En effet, durant
       la capture des géolocalisations d'un parcours qui peut durer un temps non négligeable, il
       doit être IMPERATIVEMENT POSSIBLE d'exécuter une autre application comme téléphoner par exemple
       en préservant intégralement la géolocalisation du parcours. L'aplication (1) peut donc ainsi être
       lancée et arrêtée à loisir.
       
       Les outils utilisés sont :
            - le package "android.location" pour la récupératins des géolocalisations par le service
              activité (2),
            - les "Shared Preferences" pour permettre à l'application (1) de visualiser les
              géolocalisatoions à tout moment voulu,
            - la classe publique "Handler" pour permettre à l'activité (1) de visualiser périodiquement
              le données de géolocalisations produites par le service activité (2).
    ***************************************************************************************************/
    package loupapet.test;
     
    import android.app.Activity;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences ;
    import android.os.*;
    import android.view.Menu;
    import android.view.View;
    import android.widget.TextView ;
     
    /***************************************************************************************************
                                             L'activité (1) 
    ***************************************************************************************************/
    public class Activite1 extends Activity
    {
      public static final long DELAI = 1000 ;                           // cycle d'affichage 1 seconde
     
      private SharedPreferences donnees ;
      private Handler           monHandler = new Handler() ;
     
      private Runnable monRunnable = new Runnable() 
      {
        @Override
        public void run()
        {
          affiche() ;
          monHandler.postDelayed(this,DELAI) ;              // autorelance après 'DELAI' millisecondes
        }
      } ;
     
      @Override
      protected void onCreate(Bundle savedInstanceState)
      {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activite_1);
     
        System.out.println( "Activité (1) : démarrée" ) ;
     
        donnees = getSharedPreferences( "Activité"
                                      , Context.MODE_MULTI_PROCESS
                                      ) ;
     
      //*** IL faut lancer un affichage une première fois pour initialiser le processus de répétition
      //    tant qu'à faire après 'DELAI' millisecondes :                                  
        monHandler.postDelayed(monRunnable,DELAI) ;
      }
     
      public void onPause()
      {
        super.onPause();
        if(monHandler != null)
            monHandler.removeCallbacks(monRunnable);                       // On arrete le callback
    }
    //*** On crée un menu à 3 boutons :
      @Override
      public boolean onCreateOptionsMenu(Menu menu)
      {
        getMenuInflater().inflate(R.menu.activite1, menu);
        return true;
      }
     
    //*** La méthode démarre le service : Elle lance donc l'activité (2) :
      public void startService(View view)
      {
        System.out.println ("Activité (1) : " + "lancement du service") ;
        startService(new Intent(getBaseContext(), Activite2.class));
      }
     
    //*** La méthode met fin au service et par voie de conséquence à l'activité (2) :
      public void stopService(View view)
      {
        System.out.println ("Activité (1) : " + "arrêt du service") ;
        stopService(new Intent(getBaseContext(), Activite2.class));
      }
     
      public void affiche()
      {
        String longitude = donnees.getString("longitude" , "") ;
        String latitude  = donnees.getString("latitude"  , "") ;
        String altitude  = donnees.getString("altitude"  , "") ;
        String precision = donnees.getString("precision" , "") ;
     
        ((TextView)findViewById(R.id.tvLongitude)).setText(longitude) ;
        ((TextView)findViewById(R.id.tvLatitude )).setText(latitude ) ;
        ((TextView)findViewById(R.id.tvAltitude )).setText(altitude ) ;
        ((TextView)findViewById(R.id.tvPrecision)).setText(precision) ;
      }
    }
    II - le fichier layout "activite_1.xml' :
    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
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
       android:layout_width="fill_parent"
       android:layout_height="fill_parent"
       android:orientation="vertical" >
     
       <Button android:id="@+id/btnStartService"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:text="Démarrage du service"
       android:onClick="startService"/>
     
       <Button android:id="@+id/btnStopService"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content"
       android:text="Arrêt du service"
       android:onClick="stopService" />
     
       <TextView
           android:id="@+id/tvLongitude"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:gravity="center_horizontal"
           android:text="longitude="
           android:textAppearance="?android:attr/textAppearanceLarge" />
     
       <TextView
           android:id="@+id/tvLatitude"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:gravity="center_horizontal"
           android:text="latidude="
           android:textAppearance="?android:attr/textAppearanceLarge" />
     
       <TextView
           android:id="@+id/tvAltitude"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:gravity="center_horizontal"
           android:text="altitude="
           android:textAppearance="?android:attr/textAppearanceLarge" />
     
       <TextView
           android:id="@+id/tvPrecision"
           android:layout_width="match_parent"
           android:layout_height="wrap_content"
           android:gravity="center_horizontal"
           android:text="precision="
           android:textAppearance="?android:attr/textAppearanceLarge" />
     
    </LinearLayout>
    III - Le service appelé 'activite2' :
    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
    /***************************************************************************************************
           La présente activité (2) est en réalité un service qui permet d'effectuer des captures de
       géolocalisations en arrière plan tant que l'application (1) ne lui a pas donné l'ordre de
       s'arrêter.
    ***************************************************************************************************/
    package loupapet.test;
     
    import android.app.Service;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences;
    import android.location.*;
    import android.os.* ;
    import android.os.Bundle;
    import android.os.IBinder;
     
    /**************************************************************************************************
                                             L'activité (2) 
    **************************************************************************************************/
    public class Activite2 extends Service
    {
      private LocationManager lm = null ;
      private double          latitude  ;
      private double          longitude ;
      private double          altitude  ;
      private float           precision ;
     
      private SharedPreferences donnees ;
     
    //=================================================================================================
    //                            *** Les méthodes de contrôle du service ***
    //=================================================================================================
      @Override
      public IBinder onBind(Intent arg0)                                      // Attachement du service
      {
        System.out.println( "Activité (2) : " + "Service attaché (onBind)") ;
        return null;
      }
     
      @Override
      public int onStartCommand(Intent intent, int flags, int startId)          // Démarrage du service
      {
        System.out.println ("Activité (2) : " + "Service démarré (onStartCommand)") ;
        return START_STICKY ;     // Le service continue même si l'activité qui l'a lancée est détruite
      }
     
      @Override
      public void onDestroy()                                                 // destruction du service
      { System.out.println ("Activité (2) : " + "détruite (onDestroy)") ;
        if(lm != null)
        { lm.removeUpdates(ll) ;
          System.out.println ("               " + "mises à jour supprimées") ;
        }
        lm = null;
      }
     
      @Override
      public void onRebind(Intent intent)                                   // reattachement du service
      {
        System.out.println ("Activité (2) : " + "réattachée (onRebind)") ;
      }
     
      public void onCreate()                                                     // Création du service
      {
        System.out.println ("Activité (2) : " + "Service créé (onCreate)") ;
     
        donnees = getSharedPreferences( "Activité"
                                      , Context.MODE_MULTI_PROCESS
                                      ) ;
     
      //*** Lancemant de la géolocalisation :
        lm = (LocationManager) this.getSystemService(LOCATION_SERVICE) ;
     
        if(lm != null)                                                       // pour propreté au cas où
        { lm.removeUpdates(ll) ;
          System.out.println ("               " + "mises à jour supprimées") ;
        }
        lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 5000, 0, ll) ;
      }
     
    //=================================================================================================
    //                     *** Les méthodes de traitement de la géolocalisation ***
    //=================================================================================================
      private LocationListener ll = new LocationListener()
      {
        public void onLocationChanged(Location geoloc)
        {
          latitude  = geoloc.getLatitude() ;
          longitude = geoloc.getLongitude() ;
          altitude  = geoloc.getAltitude() ;
          precision = geoloc.getAccuracy() ;
     
          System.out.println ( "Activité (2) :\n"
                             + "         - longitude=" + longitude + "\n"
                             + "         - latitude="  + latitude  + "\n"
                             + "         - altitude="  + altitude  + "\n"
                             + "         - précision=" + precision
                             )  ;
     
        //*** On dépose les données de géolocalisations pour être affichées dans l'activité (1) :
          donnees.edit().putString("longitude",String.format("%.5f",longitude))
                        .putString("latitude" ,String.format("%.5f",latitude ))
                        .putString("altitude" ,String.format("%.1f",altitude ))
                        .putString("precision",String.format("%.1f",precision))
                        .commit();
        }
     
        public void onProviderEnabled(String provider)
        {
          System.out.println ( "Activité (2) :\n"
                             + "         - " + provider + " est maintenant actif (Enabled)" 
                             ) ;
        }
     
        public void onProviderDisabled(String provider)
        {
          System.out.println ( "Activité (2) :\n"
                             + "         - " + provider + " est maintenant inactif (Disabled)" 
                             ) ;
        }
     
        public void onStatusChanged(String provider, int statut, Bundle extras)
        {
          String etat = "" ;
     
          switch (statut)
          { case LocationProvider.OUT_OF_SERVICE          : etat = "HORS_SERVICE"            ; break ;
            case LocationProvider.TEMPORARILY_UNAVAILABLE : etat = "TEMPORAIREMENT_INVALIDE" ; break ;
            case LocationProvider.AVAILABLE               : etat = "VALIDE"                  ; break;
          }
          System.out.println ( "Activité (2) :\n"
                             + "         - " + provider + " a maintenant le status " + etat ) ;
        }
      } ;
    }
    Si je vois qu'il n'y a pas de retour d'anomalies d'ici quelques jours, je marquerai la discussion comme "résolue".

    Encore merci pour votre aide.
    Bien cordialement.

    Lou Papet

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 20
    Dernier message: 29/03/2007, 20h26
  2. [VB.NET] Comment lancer une application externe dans ma Form
    Par afdmats dans le forum Windows Forms
    Réponses: 1
    Dernier message: 03/10/2006, 15h27
  3. Comment lancer une application qui a été développée sous Unix avec le navigateur IE
    Par diamonds dans le forum Applications et environnements graphiques
    Réponses: 2
    Dernier message: 26/09/2006, 14h43
  4. Réponses: 11
    Dernier message: 25/05/2006, 11h42
  5. Réponses: 1
    Dernier message: 07/02/2006, 00h11

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