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 :

Application chronomètre éxécutable que lors de l'installation


Sujet :

Android

  1. #1
    Membre émérite
    Avatar de tails
    Homme Profil pro
    Inscrit en
    Novembre 2003
    Messages
    799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations forums :
    Inscription : Novembre 2003
    Messages : 799
    Billets dans le blog
    15
    Par défaut Application chronomètre éxécutable que lors de l'installation
    Bonjour,

    je rencontre un problème en développant une application chronomètre.

    je sais qu'il existe plein d'applications Chronometre/CompteARebours sur le market, mais je voulais m'en créer un :
    • Je ne peux me permettre de me connecter à Internet vu mon forfait téléphonique
    • Cela me permettrait de progresser davantage sur Android


    Je ne pense pas que mes fichiers ressources strings.xml et colors.xml vous soient indispensables en revanche :

    code de chronometer_view.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
     
    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout
      xmlns:android="http://schemas.android.com/apk/res/android"
      android:layout_height="fill_parent"
      android:background="@color/chronometer_view_layout_background"
      android:orientation="vertical" android:layout_width="fill_parent">
    <TextView 
    android:id="@+id/valeur_chrono"
    android:textStyle="bold"
    android:typeface="monospace"
    android:text="00:00:00"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:textSize="50sp"
    android:gravity="center_horizontal"
    android:background="@color/chronometer_background"
    android:textColor="@color/chronometer_foreground"/>
    <LinearLayout 
    android:layout_width="fill_parent"
    android:background="@color/chronometer_layout_background"
    android:orientation="horizontal"
    android:layout_height="wrap_content" android:gravity="center_vertical|center_horizontal">
    <Button 
    android:id="@+id/action_chrono" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content"
    android:layout_below="@id/valeur_chrono" 
    android:text="@string/chronometer_action_text_start"
    android:textSize="8sp"/>
    <Button 
    android:id="@+id/initialisation_chrono" 
    android:layout_below="@id/valeur_chrono"
    android:layout_toRightOf="@id/action_chrono"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/initialisation_chrono_text"
    android:textSize="8sp"/>
    <Button 
    android:id="@+id/configuration_chrono" 
    android:layout_below="@id/valeur_chrono"
    android:layout_toRightOf="@id/initialisation_chrono"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:text="@string/configuration_chrono_text"
    android:textSize="8sp"/>
    </LinearLayout>
    </LinearLayout>
    code de ChronometerActivity.java
    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
     
    package org.isgreat.loloof64.android.chronometer;
     
    import java.util.Observable;
    import java.util.Observer;
     
    import android.app.Activity;
    import android.os.Bundle;
    import android.view.View;
    import android.view.View.OnClickListener;
    import android.widget.Button;
    import android.widget.TextView;
     
    public class ChronometerActivity extends Activity implements OnClickListener, Observer {
     
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.chronometer_view);
            actionButton = (Button) findViewById(R.id.action_chrono);
            resetButton = (Button) findViewById(R.id.initialisation_chrono);
            setupButton = (Button) findViewById(R.id.configuration_chrono);
            chronometerValue = (TextView) findViewById(R.id.valeur_chrono);
            actionButton.setOnClickListener(this);
            resetButton.setOnClickListener(this);
            setupButton.setOnClickListener(this);
            ////// temporaire /////////////////
            resetButton.setEnabled(false);
            setupButton.setEnabled(false);
            ///////////////////////////////////
        }
     
        @Override
        public void onResume(){
        	super.onResume();
        	chronometerMotor = new ChronometerMotor();
        	chronometerMotor.addObserver(this);
        	chronometer = new Thread(chronometerMotor);
        }
     
    	@Override
    	public void onClick(final View view) {
    		new Thread(){
     
    			{
    				setDaemon(true);
    			}
     
    			public void run(){
    				if (view == actionButton){
    					toggleChronometerState();
    				}
    				else if (view == resetButton){
    					resetChronometer();
    				}
    				else if (view == setupButton){
    					showSetupScreen();
    				}
    			}
    		}.start();
    	}
     
    	@Override
    	public void update(Observable observable, final Object data) {
    		runOnUiThread(new Thread(){
    			public void run(){
    				long totalSeconds = (Long) data;
    				String timeString = getTimeString(totalSeconds);
    				chronometerValue.setText(timeString);
    			}
    		});
    	}
     
    	private String getTimeString(long totalSeconds) {
    		int seconds = (int) totalSeconds % 60;
    		int minits = (int) (totalSeconds / 60) % 60;
    		int hours = (int) totalSeconds / 3600;
    		return String.format("%02d:%02d:%02d", hours, minits, seconds);
    	}
     
    	private void showSetupScreen() {
    		throw new UnsupportedOperationException();
    	}
     
    	private void resetChronometer() {
    		throw new UnsupportedOperationException();
    	}
     
    	private void toggleChronometerState() {
    		if ( ! chronometer.isAlive() )
    			chronometer.start();
    		else
    			chronometerMotor.toggleState();
    	}
     
    	private Button actionButton;
    	private Button resetButton;
    	private Button setupButton;
    	private TextView chronometerValue;
    	private ChronometerMotor chronometerMotor;
        private Thread chronometer;
    }
    code de ChronometerMotor.java
    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
     
    package org.isgreat.loloof64.android.chronometer;
     
    import java.util.Observable;
     
    public class ChronometerMotor extends Observable implements Runnable {
     
    	public ChronometerMotor(){
    	}
     
    	@Override
    	public void run() {
    		while(true){
    			try {
    				Thread.sleep(1000);
    			} catch (InterruptedException exception) {
    				exception.printStackTrace();
    			}
    			/*
    			 * Causera certainement des soucis de Garbage Collection
    			 * Mais en attedant de trouver mieux ...
    			 */
    			new UpdateThread().start();
    		}
    	}
     
    	public void toggleState(){
    		//Non supporté pour le moment	
    	}
     
    	private class UpdateThread extends Thread{
     
    		public UpdateThread(){
    			setDaemon(true);
    		}
     
    		public void run(){
    			totalSeconds++;
    			setChanged();
    			notifyObservers(totalSeconds);
    		}
    	}
     
    	private long totalSeconds;
    }
    Le problème c'est que le code s'éxécute normallement sitôt que je le lance depuis Eclipse, et que je clique sur le bouton Demarrer (le bouton actionButton dans l'activité). Mais dès que je quitte l'application avec le bouton Return ou Home, et je clique sur le raccourcis de mon émulateur, j'ai une exception
    Affichage du Logcat pour l'exception
    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
     
    11-26 15:42:18.141: ERROR/AndroidRuntime(6113): Uncaught handler: thread main exiting due to uncaught exception
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113): java.lang.RuntimeException: Unable to instantiate activity ComponentInfo{org.isgreat.loloof64/org.isgreat.loloof64.ChronometerActivity}: java.lang.ClassNotFoundException: org.isgreat.loloof64.ChronometerActivity in loader dalvik.system.PathClassLoader@437358a0
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2194)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at android.app.ActivityThread.access$1800(ActivityThread.java:112)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at android.os.Handler.dispatchMessage(Handler.java:99)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at android.os.Looper.loop(Looper.java:123)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at android.app.ActivityThread.main(ActivityThread.java:3948)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at java.lang.reflect.Method.invokeNative(Native Method)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at java.lang.reflect.Method.invoke(Method.java:521)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at dalvik.system.NativeStart.main(Native Method)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113): Caused by: java.lang.ClassNotFoundException: org.isgreat.loloof64.ChronometerActivity in loader dalvik.system.PathClassLoader@437358a0
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at dalvik.system.PathClassLoader.findClass(PathClassLoader.java:243)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at java.lang.ClassLoader.loadClass(ClassLoader.java:573)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at java.lang.ClassLoader.loadClass(ClassLoader.java:532)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at android.app.Instrumentation.newActivity(Instrumentation.java:1097)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2186)
    11-26 15:42:18.169: ERROR/AndroidRuntime(6113):     ... 11 more
    J'ai aussi une deuxième question :
    Vous avez certainement remarqué le commentaire dans la classe ChronometerMotor, à propos du ramasse-miettes. Je crée un nouveau Thread pour libérer la boucle principale de comptage, et ainsi réaliser les opérations de mise à jour de manière plus efficace. Mais, comment obtenir le même résultat en évitant de libérer l'instance courante de Thread et créer une nouvelle à chaque fois ? J'ai essayé de m'aventurer dans le Thread.wait() et Thread.notify ... sans grand succès.

  2. #2
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Pour l'erreur je ne sais pas si le while(true) sans le forcer à se fermer est une bonne idée lorsque l'activity se ferme.


    Pour ta deuxième question , je te suggère de passer par les Handlers .

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    private final int TimeDelay = 1000; // 1s
     
    Handler mHandler = new Handler()
    mHandler.postDelayed(mRun, TimeDelay);
     
    private Runnable mRun = new Runnable() {
    		public void run() {
     
                        mHandler.removeCallbacks(mRun);
                        mHandler.postDelayed(mRun, TimeDelay);
                    }
    };

  3. #3
    Membre émérite
    Avatar de tails
    Homme Profil pro
    Inscrit en
    Novembre 2003
    Messages
    799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations forums :
    Inscription : Novembre 2003
    Messages : 799
    Billets dans le blog
    15
    Par défaut
    Bonjour Feanorin,

    merci pour tes propositions

    En fait le while(true), c'est une habitude que j'ai prise pour les Threads. Et j'avais totalement négligé de prévoir un moyen de le faire quitter lorsque l'activité se termine. Néanmoins, je suis sûr qu'il est possible laisser le chronometre actif et de voir la valeur mise à jour en retournant dans l'activité : j'ai déjà vu un Chronometre fonctionner ainsi et qui renvoyait même régulièrement des notifications. Mais bon, peut être que pour le moment je devrais me contenter de faire simple et arrêter complètement la boucle while(true).

    Je vais essayer d'utiliser les Handlers.

    Merci beaucoup. Si j'ai réussi je passerais le sujet en résolu.

  4. #4
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    Tu peux passer ton chronomètre dans un Service , il tournera en fond et tu pourra le récupérer quand tu veux .

    Pour le while(true) , je n'en suis pas sûr c'est juste un supposition, normalement ça ne doit pas influer , mais bon .

  5. #5
    Membre émérite
    Avatar de tails
    Homme Profil pro
    Inscrit en
    Novembre 2003
    Messages
    799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations forums :
    Inscription : Novembre 2003
    Messages : 799
    Billets dans le blog
    15
    Par défaut J'ai essayé autre chose : sans succes
    (Je n'avais pas lu ton dernier message)

    J'ai fais des modifications, sans y parvenir (le chronomètre ne demarre pas)

    classe ChronometerMotor.java

    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
     
    package org.isgreat.loloof64.android.chronometer;
     
    import java.util.Observable;
     
    import android.os.Handler;
     
    public class ChronometerMotor extends Observable implements Runnable {
     
    	public void setChanged(){
    		super.setChanged();
    	}
     
    	public void run(){
    		while( ! appFinished ){
    			if ( ! appSuspended ){
    				myHandler.postDelayed(chronometerSnoozer, delayMilliSeconds);
    			}
    		}
    	}
     
    	private class MyChronometerMotorSnoozer implements Runnable {
     
    		@Override
    		public void run() {
    			updater.releaseWaiting();
    			myHandler.removeCallbacks(chronometerSnoozer);
    			myHandler.postDelayed(chronometerSnoozer, delayMilliSeconds);
    		}
     
    		private MyChronometerMotorUpdater updater = new MyChronometerMotorUpdater();
     
    	}
     
    	private class MyChronometerMotorUpdater extends Thread {
    		@Override
    		public void run(){
    			while ( ! appFinished ) {
    				if ( ! isWaiting ) {
    					totalSeconds++;
    					setChanged();
    					notifyObservers();
    					isWaiting = true;
    				}
    			}
    		}
     
    		public void releaseWaiting(){
    			isWaiting = false;
    		}
     
    		private boolean isWaiting;
    	}
     
    	public void toggleState(){
    		appSuspended = ! appSuspended;
    	}
     
    	private long totalSeconds;
    	private int delayMilliSeconds = 1000;
    	private Handler myHandler = new Handler();
    	private MyChronometerMotorSnoozer chronometerSnoozer = new MyChronometerMotorSnoozer();
    	private boolean appFinished;
    	private boolean appSuspended = true;
    }
    En fait je veux vraiment lancer le "compteur" et la mise à jour dans deux Threads différents (donc disposer de 3 Threads) car dans ce cas j'utilise le Design Pattern Observer pré-implémenté par Java : java.util.Observer et java.util.Observable. Et donc, l'appel à notifyObservers risque de ralentir un peu le compteur si j'ai plus d'un Observer sur le ChronometerMotor. Mais, je suis peut être ambitieux.

    Si toi ou quelqu'un d'autre a la solution , je serais plus que preneur (en l'ayant essayé bien sûr).

    Ensuite, je m’intéresserais aux Services pour le lancer en tâche de fond (merci )

  6. #6
    Expert confirmé

    Avatar de Feanorin
    Profil pro
    Inscrit en
    Avril 2004
    Messages
    4 589
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2004
    Messages : 4 589
    Par défaut
    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
     
    package org.isgreat.loloof64.android.chronometer;
     
    import java.util.Observable;
     
    import android.os.Handler;
     
    public class ChronometerMotor extends Observable implements Runnable {
     
    	public void setChanged(){
    		super.setChanged();
    	}
     
    	public void run(){
    		myHandler.postDelayed(chronometerSnoozer, delayMilliSeconds);
    	}
     
            private MyChronometerMotorSnoozer chronometerSnoozer = new MyChronometerMotorSnoozer();
    	private class MyChronometerMotorSnoozer implements Runnable {
     
    		@Override
    		public void run() {
    			totalSeconds++;
    			setChanged();
    			notifyObservers();
    			myHandler.removeCallbacks(chronometerSnoozer);
    			myHandler.postDelayed(chronometerSnoozer, delayMilliSeconds);
    		}
     
     
     
    	}
     
     
    	private long totalSeconds;
    	private int delayMilliSeconds = 1000;
    	private Handler myHandler = new Handler();
    }

  7. #7
    Membre émérite
    Avatar de tails
    Homme Profil pro
    Inscrit en
    Novembre 2003
    Messages
    799
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Pyrénées Atlantiques (Aquitaine)

    Informations forums :
    Inscription : Novembre 2003
    Messages : 799
    Billets dans le blog
    15
    Par défaut Merci :)
    Merci beaucoup pour ton code
    Le problème du redemarrage d'activité est résolu.

    Je pense avoir compris, la gestion des Handlers offre le même résultat que ma fameuse boucle infinie : la souplesse en plus.

    J'ai juste dû, par contre, modifier la ligne suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    notifyObservers();
    par
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    notifyObservers(totalSeconds);
    Car en effet, dans la classe ChronometerActivity.java je recupère, dans la méthode update, la valeur de totalSeconds.

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

Discussions similaires

  1. Réponses: 2
    Dernier message: 21/04/2008, 11h23
  2. Problème lors de l'installation de mon application VB SQL
    Par Koukouknizou dans le forum Installation, Déploiement et Sécurité
    Réponses: 3
    Dernier message: 12/12/2007, 20h47
  3. Erreur lors de l'installation d'une application VB
    Par akesjv dans le forum Installation, Déploiement et Sécurité
    Réponses: 1
    Dernier message: 27/03/2007, 11h41
  4. Réponses: 2
    Dernier message: 30/01/2007, 11h08
  5. Erreur lors de l'installation d'une application
    Par omlip dans le forum Tomcat et TomEE
    Réponses: 1
    Dernier message: 16/11/2006, 12h21

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