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 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 <?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 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
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; }
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
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; }
Affichage du Logcat pour l'exception
J'ai aussi une deuxième question :
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
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.
Partager