Android, un cours complet

Mathias Seguy

- Titre : Android, un cours complet

- Auteur : Mathias Seguy

- Parution : 5 mai 2016

- Licence : Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright ® 2016 Mathias Seguy. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Mon application est un Service

- I-A. Utilisation d'un service

- I-B. Création d'un service

- II. Le fichier manifest.xml

I - Mon application est un Service

Un service, c'est un démon, une thread qui tourne sans IHM, bref un service. Un service est un singleton ou presque. En effet, si plusieurs processus accèdent au service, il n'y aura qu'un service. Mais si le service n'a plus d'utilisateur alors le singleton est détruit et le prochain utilisateur recrée un autre singleton. Cela paraît anodin, mais si votre service lance une thread puis est détruit et recréé alors il lancera une nouvelle thread, oubliant la précédente…

L'exemple typique d'un service est votre lecteur de musique. Quand le lecteur n'est plus au premier plan, la musique continue à être jouée, c'est un service. Si ce n'était qu'une activité, dés que l'activité aurait quitté le premier plan, la musique se serait arrêtée.

Un service se lance soit manuellement par l'utilisateur, soit par un appel d'un autre processus. Puis, il reste en vie jusqu'à ce qu'il ne soit plus nécessaire. De ce fait, il doit être très peu gourmant en CPU (au risque de vider la batterie trop vite) et en mémoire (au risque de saturer l'appareil trop vite).

Enfin, soit votre service est interne à votre application et n'a pas de vocation à être ouvert sur le reste du système, soit il a pour vocation d'être ouvert au système. Ces deux cas de figure sont profondément différents et dans l'implémentation et dans l'utilisation du service. Nous n'exposerons ici que le cas d'un service ouvert au reste du monde.

I-A - Utilisation d'un service

Il faut implémenter sept choses dans votre Activity pour pouvoir utiliser un service:

- Un objet Service qui n'est autre qu'un pointeur vers le service que vous souhaitez utiliser.

- Un objet ServiceConnection dont le but est de gérer la connexion et la déconnexion au service.

- Un objet BroadCastReceiver pour pouvoir écouter les modifications envoyées par le service

- Un appel à la méthode bindService(service, serviceConnection, flags) dans votre méthode onCreate

- Un appel à la méthode unbindService(serviceConnection) dans votre méthode onDestroy

- Un appel à la méthode registerReceiver(broadcastReceiver, filter) dans votre méthode onResume pour pouvoir écouter les intentions envoyées par le service. Ce mécanisme permet au service d'informer l'activité d'un changement.

- Un appel à la méthode unregisterReceiver(broadcastReceiver) dans votre méthode onPause pour stopper l'écoute des modifications envoyées par le service.

Ce qui donne l'exemple élémentaire suivant :

1. public class MyServiceUser extends Activity {

2. /**

3. * The service that can be used as a normal object You can call its   public methods

4. */

5. private MyService appService = null;

6. /**

7. * The broadcast receiver that aims to listen to change broadcast by the service

8. */

9. private BroadcastReceiver receiver = new BroadcastReceiver() {

10. public void onReceive(Context context, Intent intent) {

11. // Do something, call a method, you already know your service

12. // you can use its methods directly in your code

13. }

14. };

15. /**

16. * The service connection, that aims to connect to the service

17. */

18. private ServiceConnection onService = new ServiceConnection() {

19. /* (non-Javadoc)

20. * @see  android.content.ServiceConnection#onServiceConnected(android.content.ComponentName,* android.os.Ibinder)

21. */

22. public void onServiceConnected(ComponentName className, IBinder rawBinder) {

23. appService = ((MyService.LocalBinder) rawBinder).getService();

24. }

26. /* (non-Javadoc)

27. * @see

28. * android.content.ServiceConnection#onServiceDisconnected(android.content.ComponentName)

29. */

30. public void onServiceDisconnected(ComponentName className) {

31. appService = null;

32. }

33. };

34. @Override

35. public void onCreate(Bundle savedInstanceState) {

36. super.onCreate(savedInstanceState);

37. setContentView(R.layout.main);

38. ...

39. //Bind your service to your activity.

40. //The parameters are: The intent to talk to the service, the service connection

41. //to use and a flag to indicates if the service has to automaticly start or not

42. //You should use BIND_AUTO_CREATE

43. bindService(new Intent(this, MyService.class),onService,    Context.BIND_AUTO_CREATE);

44. }

46. @Override

47. public void onResume() {

48. super.onResume();

49. //Register your activity to listen for change send by the service

50. //You can here see that the service has declared a Static public     String BROADCAST_ACTION //that is used to identify the Intent with unicity

51. registerReceiver(receiver, new       IntentFilter(MyService.BROADCAST_ACTION));

52. }

54. @Override

55. public void onPause() {

56. super.onPause();

57. //Unregister your activity to listen for change send by the service

58. unregisterReceiver(receiver);

59. }

61. @Override

62. public void onDestroy() {

63. super.onDestroy();

64. //Unbind your service (else your activity will be destroyed but your service

65. //will still think that somebody use it

66. unbindService(onService);

67. }

69. }

I-B - Création d'un service

Lors de la création d'un service, gardez en tête que celui-ci s'exécute par défaut dans la thread principale de votre application. C'est à vous de faire en sorte de créer une thread pour que votre service l'utilise et ne court-circuite pas votre activité principale.

Pour créer un service, vous devez implémenter :

- la méthode onCreate() qui a à charge l'initialisation

- la méthode onDestroy qui a à charge la destruction de votre service une classe privée qui étend Binder

- la méthode onBind qui renvoie votre classe privée qui étend Binder

- un attribut public static final qui n'est autre que votre identifiant d'intention

- la classe de traitement dans une thread parallèle pour effectuer les actions de votre service. Cette classe étend AsyncTask.

1. /**

2. * @author mathias1

3. * @goals This class aims to show a service's skeleton

4. */

5. public class MyService extends Service {

6. /*****************************************************************************************/

7. /** Managing initialisation and death ***************************************************/  /*********************************************************************************

9. /*

10. * (non-Javadoc)

11. *

12. * @see android.app.Service#onCreate()

13. */

14. @Override

15. public void onCreate() {

16. super.onCreate();

17. //initialize your service here

18. }

20. /*

21. * (non-Javadoc)

22. *

23. * @see android.app.Service#onDestroy()

24. */

25. @Override

26. public void onDestroy() {

27. super.onDestroy();

28. //destroy your service here

29. }

31. /****************************************************************************************/

32. /** Managing the binder to this service*********************************************************/    /****************************************************************************************/

33. /**

34. * The binder that glue to my service

35. */

36. private final Binder binder=new LocalBinder();

37. /**

38. * @author mSeguy

39. * @goals This class aims to define the binder to use for my service

40. */

41. public class LocalBinder extends Binder {

42. /**

43. * @return the service you want to bind to : i.e. this

44. */

45. MyService getService() {

46. return (MyService.this);

47. }

48. }

49. /* (non-Javadoc)

50. * @see android.app.Service#onBind(android.content.Intent)   */

51. @Override

52. public IBinder onBind(Intent intent) {

53. return binder;

54. }

56. /*****************************************************************************************/

57. /** Managing the Communication between the service and its listeners **********************/

58. /****************************************************************************************/

59. /**

60. * The key of the Intent to communicate with the service's users

61. */

62. public static final String MY_SERVICE_INTENT = "stinfoservices.net.android.MyUniqueItentServiceKey";

63. /**

64. * The intent itself

65. */

66. private Intent broadcast = new Intent(MY_SERVICE_INTENT);

68. /**

69. * @author mSeguy

70. * @goals

71. * This class aims to make a task in a separeted thread

72. */

73. class MyTaskInAnOtherThread extends AsyncTask<Location, Void, Void> {

74. @Override

75. protected Void doInBackground(Location... locs) {

76. // Do something to update your data

77. // here is the place where your treatment is done in another thread than in the GUI

78. // thread

80. // Prevent your listener that something happens

81. sendBroadcast(broadcast);

82. return (null);

83. }

85. @Override

86. protected void onProgressUpdate(Void... unused) {

87. // not needed here

88. }

90. @Override

91. protected void onPostExecute(Void unused) {

92. // not needed here

93. }

94. }

95. }

II - Le fichier manifest.xml

Le fichier manifest.xml est décrit de manière complète à la page :

http://developer.android.com/guide/topics/manifest/manifest-intro.html

Ce fichier est le centre névralgique de votre application et ce pour plusieurs raisons :

- D'une part il décrit les besoins de votre application, en termes de SDK, de compatibilité matérielle, d'API utilisées et d'utilisation de services du système,

- D'autre part, il décrit ce qu'offre votre application au système (Activity, ContentProvider, Service…),

- Enfin, il décrit les éléments auxquels votre application réagit au moyen des IntentFilters et d'URI ainsi que les permissions nécessaire pour les utiliser.

Ce fichier est analysé par les markets pour cibler les appareils qui sont éligibles pour le téléchargement de votre application. Il faut donc être très attentif à sa mise en place.

Pour décrire ces éléments, ce fichier possède la structure globale suivante :

<manifest>

<uses-permission />
<permission />
<permission-tree />
<permission-group />
<instrumentation />
<uses-sdk />
<uses-configuration />
<uses-feature />
<supports-screens />
<compatible-screens />
<supports-gl-texture />

<application>

<activity>
<intent-filter>
<action />
<category />
<data />
</intent-filter>
<meta-data />
</activity>

<activity-alias>
<intent-filter> . . . </intent-filter>
<meta-data />
</activity-alias>

<service>
<intent-filter> . . . </intent-filter>
<meta-data/>
</service>

<receiver>
<intent-filter> . . . </intent-filter>
<meta-data />
</receiver>

<provider>
<grant-uri-permission />
<meta-data />
</provider>

<uses-library />

</application>

</manifest>

N'hésitez pas à assouvir votre curiosité en allant sur la page précédemment citée pour connaître chacune de ces balises.