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 :

AlarmReceiver qui se connecte à un Service


Sujet :

Android

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Géochimiste
    Inscrit en
    Août 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Géochimiste

    Informations forums :
    Inscription : Août 2012
    Messages : 20
    Par défaut AlarmReceiver qui se connecte à un Service
    Bonjour à tous,
    je développe une application qui permet de programmer le lancement d'un service à une date et heure précise et d'effectuer certaines taches de fond.

    Pour cela j'ai une activité (MainActivity) qui me permet de gérer l'interface graphique et contient la méthode (planifierAlarm) pour paramétrer la class AlarmReceiver, un Service (MyService) et une class AlarmReceiver.

    (Code trouvé sur un autre site)

    MainActivity :
    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
     
    ...
    private void planifierAlarm() {
    //Récupération de l'instance du service AlarmManager.
    AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
     
    //On instancie l'Intent qui va être appelé au moment du reveil.
    Intent intent = new Intent(this, AlarmReceiver.class);
     
    //On créer le pending Intent qui identifie l'Intent de reveil avec un ID et un/des flag(s)
    PendingIntent pendingintent = PendingIntent.getBroadcast(this, ALARM_ID, intent, 0);
     
    //On annule l'alarm pour replanifier si besoin
    am.cancel(pendingintent);
     
    if(alarm.isActive()){
    //on va déclencher un calcul pour connaitre le temps qui nous sépare du prochain reveil.
    Calendar reveil  = Calendar.getInstance();
    reveil.set(Calendar.HOUR_OF_DAY, alarm.getHeure().hour);
    reveil.set(Calendar.MINUTE, alarm.getHeure().minute);
    if(reveil.compareTo(Calendar.getInstance()) == -1)
    reveil.add(Calendar.DAY_OF_YEAR, 1);
    Calendar cal = Calendar.getInstance();
    reveil.set(Calendar.SECOND, 0);
    cal.set(Calendar.SECOND, 0);
    long diff = reveil.getTimeInMillis() - cal.getTimeInMillis();
     
    //On ajoute le reveil au service de l'AlarmManager
    am.set(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis() + diff, pendingintent);
    Toast.makeText(this, "Alarme programmé le " + reveil.get(Calendar.DAY_OF_MONTH) + " à " + reveil.get(Calendar.HOUR_OF_DAY) + ":" + reveil.get(Calendar.MINUTE), Toast.LENGTH_SHORT).show();
    }
    }
     
    ...

    AlarmReceiver :
    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
     
    ...
    @Override
    	public void onReceive(Context context, Intent intent)
    	{
    		connection = new ServiceConnection()
            {
                public void onServiceConnected(ComponentName name, IBinder service)
                {
               	 myService = (MyService) ((MyService.BackgroundServiceBinder)service).getService();
    	         //appel de la méthode (plus bas)
                     onServiceAvailable();
                }
     
                public void onServiceDisconnected(ComponentName name)
                {
               	 myService = null;
                }  
            };
     
    	Intent serviceIntent = new Intent(context, MyService.class);
            context.startService(serviceIntent);
            context.bindService(intent,connection, Context.BIND_AUTO_CREATE);
    	}
     
    	public void onServiceAvailable()
    	 {
                   //Ici je veux accéder aux méthodes du service pour exécuter certaines taches en fond.
                   //ex. myService.sauvegardeParametres();
    	 }
    ...
    Mon problème est que lorsque je programme le lancement du service via l'AlarmReceiver, au moment du lancement, j'ai une erreur du type :
    IntentReceiver components are not allowed to bind to services

    j'ai essayé de supprimer le bind entre la class AlarmReceiver et le service et je n'ai effectivement plus d'erreur. Le service se lance correctement (je le vois dans les Log).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    @Override
    	public void onReceive(Context context, Intent intent)
    	{
    	Intent serviceIntent = new Intent(context, MyService.class);
            context.startService(serviceIntent);
    	}
    mais malheureusement je ne peux pas appeler les méthodes qui se trouvent dans le service à partir de AlarmReceiver.
    J'ai d'autres Activités qui se connectent au même service et je souhaite pouvoir programmer le lancement d'un nombre défini de méthodes de ce service.


    J'ai lu quelque part qu'il n'était pas possible de connecter un Receiver à un service, car celui-ci n'est fait que pour des actions qui ne sont pas censées durer dans le temps.

    Je me prends la tête depuis deux jours pour trouver une solution à mon problème.
    Y-a-t-il quelqu'un qui aurait une idée please ???
    Merci d'avance....

  2. #2
    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
    Pourquoi ce code ?
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    long diff = reveil.getTimeInMillis() - cal.getTimeInMillis();
    //On ajoute le reveil au service de l'AlarmManager
    am.set(AlarmManager.RTC_WAKEUP,cal.getTimeInMillis() + diff, pendingintent);
    Autant faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //On ajoute le reveil au service de l'AlarmManager
    am.set(AlarmManager.RTC_WAKEUP,reveil.getTimeInMillis(), pendingintent);
    non ?

    Sinon, il est même recommandé d'appeler DIRECTEMENT le service... qui lui lancera une UI si besoin... Regarder l'implémentation des BroadcastReceiver (pour les widget par exemple).

    Le receiver recoit un 'intent' (le PendingIntent) de là il va décider de démarrer un service ou une application, par exemple dans le onReceive:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    Intent serviceIntent = new Intent(context, MyService.class);
    serviceIntent.setAction(ACTION_A_REALISER);
    serviceIntent.putExtra(... les parametres de l'action ...);
    context.startService(serviceIntent);
    La réponse à l'évenement sera donc très rapide... et démarrera un service avec l'intent voulu. Pas besoin de faire de 'bind' (puisqu'on n'utilisera plus de fonction dessus).

  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 viens de finir ton message en fait et c'est grosso modo ce que tu as essayé... :cool:

    Donc ben c'est la bonne voie....

    La question c'est pourquoi vouloir appeler des fonctions du service dans le AlarmManager ?
    En général, l'architecture d'une appli est la suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Receiver => Service => Manager => données de l'appli
               Activité =>

  4. #4
    Membre averti
    Homme Profil pro
    Géochimiste
    Inscrit en
    Août 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Géochimiste

    Informations forums :
    Inscription : Août 2012
    Messages : 20
    Par défaut
    Citation Envoyé par nicroman Voir le message
    Pourquoi ce code ?
    ...
    Autant faire:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    //On ajoute le reveil au service de l'AlarmManager
    am.set(AlarmManager.RTC_WAKEUP,reveil.getTimeInMillis(), pendingintent);
    non ?
    Salut nicroman et merci pour ta réponse.
    A vrai dire mon script n'est pas exactement comment ça, la programmation de mon alarme est plus développée que ça. Pour simplifier j'ai fait un copier/coller du tuto que j'ai utilisé. Bref, c'est une parenthèse car ce n'est pas le sujet de mon problème ...Mais merci pour cette précision...

    La réponse à l'évenement sera donc très rapide... et démarrera un service avec l'intent voulu. Pas besoin de faire de 'bind' (puisqu'on n'utilisera plus de fonction dessus).
    C'est bien ce que je pensais.....

    Pardonne moi par avance si mes questions te semblent un peu naives, mais je ne suis pas développeur et j'ai appris sur le tas pour mon véritable métier qui est la géochimie. Il me manque donc beaucoup de bases qui semblent évidentes pour une personne qui a étudié ça à l'école.

    tu as ajouté ceci:
    serviceIntent.setAction(ACTION_A_REALISER);
    je ne comprends pas comment utiliser cette méthode et surtout ce qu'elle fait exactement. J'ai fait quelques recherches sur g***** et je n'ai trouvé que des exemples d'utilisation pour les services propres à android (ex. Intent.ACTION_CALL) et non pour les services "personnels". Comment l'utiliser et surtout quel est sont action ?

    Receiver => Service => Manager => données de l'appli
    Activité =>
    Ceci est très intéressent pour moi, c'est ce que je te disais, il me manque ce genre de bases sur l'architecture des applications. Je comprends bien Receiver => Service, mais Manager => données de l'appli, c'est un peu flou pour moi.....Qu'est ce que Manager ? Peux tu me donner plus de détails s'il te plait ?

    Sinon ton idée d'envoyer un extra au service me donne une piste. J'avais pensé envoyer une valeur (ex.boolean) au service qui déclenchera ou non les méthodes voulues.
    Ceci permettra au service de savoir qu'il a bien reçu une instruction de AlarmReceiver.
    Vois-tu une problématique, que je ne serais capable de déceler, à cette façon de faire ?
    J'essaye et je te tiens au courant.

  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
    Pour les Intent, il faut lire la documentation google sur les Intent, car c'est la base d'Android...

    Grosso-modo, un Intent est la combinaison de 5 choses:
    a) Une 'action' (il existe certaines actions prédéfinies dans android comme VIEW, EDIT, PICK, ...)
    b) Une 'url' (qui représente l'objet précis sur lequel l'action est à réaliser)
    c) Un 'mime-type' (qui indique le type de données sur lequel l'action est à réaliser)
    d) Une 'activité' ou un 'service' (d'une application) qui indique quelle activité (ou 'service') lancer.
    e) Des paramètres (sous la forme de bundle: les 'extra').

    Quand un Intent est lancé, le système va trouver la meilleur 'classe' pour gérer cet intent... Que ce soit une activité, ou que ce soit un receiver (les intent-filter déclarés dans le manifest).
    Donc par exemple, un ACTION_EDIT lancé sur un mime-type "image" va essayer de trouver un éditeur d'image... Si plusieurs 'applications' peuvent correspondre, le système demandera à l'utilisateur de choisir...

    Bien entendu, si (d) est renseigné directement, cette partie est ignorée, et l'objet (activité, ou service) est directement utilisé... C'est comme cela qu'on réalise une navigation entre plusieurs activité... Mais prenons un cas simple... une activité de "fiche de renseignement" peut répondre à deux intents: ACTION_VIEW (qui affichera un layout de simple affichage) et ACTION_EDIT (qui affichera un layout permetant d'éditer les renseignements)... Ainsi, un service (ou une activité) peut répondre à plusieurs intent différents (généralement en fonction de (a))

    Donc on peut très bien envoyer des 'Intent' différents à un Service... Hériter de IntentService aide bien à ce sujet


    Pour la partie "manager"... En général le code se divise en 4 parties:
    * La gestion des données pures (sauvegardes locales, database, ...). Par exemple "sauvegarde de Ingrédient", "sauvegarde de Recette".
    * La "business logic" (la logique de l'application). Par exemple si on modifie telle recette, on doit modifier les ingrédients de telle et telle manière, puis tout sauver. Elle s'appuie forcément sur la précédente.
    * L'étape de "commande/validation" (aussi souvent appelée 'controlleur') qui va vérifier que les commandes effectuées respectent bien les contraintes voulues (une adresse e-mail est valide, etc...).
    * L'étape de "présentation" qui va afficher les données à l'utilisateur.

    Tous les programmes suivent ces couches, maladroitement quand elles sont toutes mélangées, ou proprement (packages différents par exemple).
    Même le modèle MVC (que je déteste, mais qui a son heure de gloire) suit le même principe (chercher sur le net).

    Donc... on a les données (couche 'données') c'est facile.
    On a un (ou des) "manager" (la partie 'business logic') capable d'effectuer toutes les opérations nécessaires au bon fonctionnement de l'application.
    Ensuite, comment pilote-t-on ce(s) manager(s) ? Ou directement depuis un service (commande/validation, pas de présentation), ou depuis une activité (présentation, mais aussi commande/validation).

    Il est bien sur possible de rajouter une couche supplémentaire pour les commande/validaiton (le service ne servant alors que de décodeur d'Intent).

  6. #6
    Membre averti
    Homme Profil pro
    Géochimiste
    Inscrit en
    Août 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Géochimiste

    Informations forums :
    Inscription : Août 2012
    Messages : 20
    Par défaut
    nicroman, tu es un pro !!!

    Vraiment merci beaucoup d'avoir pris de ton temps pour m'expliquer de manière claire, précise et surtout concise les rudiments de l'architecture d'une application android.
    J'avais à peu près imaginé cela de manière intuitive car c'est du bon sens, mais je n'ai jamais eu une idée aussi claire de cette architecture (maintenant oui grace à toi ).

    Je n'ai pas encore avancé sur le script en raison des fêtes....Je te tiens au courant.....
    Très bonnes fêtes à toi

  7. #7
    Membre averti
    Homme Profil pro
    Géochimiste
    Inscrit en
    Août 2012
    Messages
    20
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Géochimiste

    Informations forums :
    Inscription : Août 2012
    Messages : 20
    Par défaut
    ça fonctionne !!!!
    Je dois dire que tu m'as grandement aidé en me mettant sur la piste de l'utilisation d'un extra.....

    Voici ma démarche.
    j'envoie un extra depuis AlarmReceiver vers le service.
    dans le onStartCommand du service, je teste la valeur de l'extra. Si la valeur de l'extra n'est pas null, le service sait que que l'alarmReceiver vient de lui envoyer quelque chose et il peut faire ce qu'il a à faire. Etant donné que les Receiver sont éphémères la valeur de l'extra n'est pas null seulement quand l'AlarmReceiver est lancé.
    C'est exactement ce que je voulais faire et cela fonctionne parfaitement.....

    Je vais quand même me pencher sur toutes les infos que tu m'as donné sur l'architecture des applications android.
    Encore merci pour tout nicroman.
    bon bout d'an !!!

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

Discussions similaires

  1. Réponses: 6
    Dernier message: 28/10/2008, 16h50
  2. [Système] Savoir qui est connecté en ce moment
    Par sourivore dans le forum Langage
    Réponses: 13
    Dernier message: 12/06/2006, 17h05
  3. Savoir qui est connecté
    Par Mat5725 dans le forum Langage
    Réponses: 2
    Dernier message: 18/10/2005, 13h06
  4. Global.asa : Qui est connecté
    Par eowene dans le forum ASP
    Réponses: 14
    Dernier message: 02/02/2005, 19h38
  5. Réponses: 2
    Dernier message: 26/08/2003, 14h21

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