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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    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
    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 693
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 41
    Localisation : France, Côte d'Or (Bourgogne)

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

    Informations forums :
    Inscription : Août 2003
    Messages : 6 693
    Par défaut
    Tu dois utiliser un service pour faire ce que tu veux faire , pas une activity
    Pry Framework php5 | N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre confirmé Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    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
    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 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
    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 confirmé Avatar de loupapet
    Homme Profil pro
    Retraité d'Eurocopter
    Inscrit en
    Janvier 2009
    Messages
    69
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 84
    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
    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 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
    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());

+ 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