Dans ce didacticiel, vous vous familiariserez avec le concept de réflexion Java: possibilité pour une classe ou un objet d’examiner par programme les détails de sa propre implémentation..
Les applications Android sont écrites en Java, un langage de programmation qui prend en charge la réflexion, c'est-à-dire la capacité d'un objet à s'auto-examiner. Dans ce didacticiel, vous apprendrez les bases de la réflexion en Java, y compris comment inspecter les méthodes et les champs d’une classe donnée, vérifier la disponibilité de méthodes spécifiques et d’autres tâches pratiques que vous devrez peut-être utiliser lors du développement pour différentes versions de le SDK Android.
Techniquement, vous n'avez besoin d'aucun outil pour compléter ce didacticiel, mais vous en aurez certainement besoin pour développer des applications Android..
Pour développer des applications Android (ou des applications Java, d'ailleurs), vous avez besoin d'un environnement de développement pour écrire et créer des applications. Eclipse est un environnement de développement (IDE) très populaire pour Java et l'IDE préféré pour le développement Android. Il est disponible gratuitement pour les systèmes d'exploitation Windows, Mac et Linux..
Pour des instructions complètes sur l'installation d'Eclipse (y compris les versions prises en charge) et le SDK Android, voir le site Web du développeur Android..
Reflection offre aux développeurs la possibilité d'inspecter et de déterminer les caractéristiques des API au moment de l'exécution, au lieu de les compiler. Dans le cadre des contraintes de sécurité imposées par Java (utilisation de public, protected, private, par exemple), vous pouvez ensuite construire des objets, des champs d'accès et des méthodes d'appel de manière dynamique. Les API Java Reflection sont disponibles dans le package java.lang.reflect, inclus dans le SDK Android à l’intention des développeurs..
Alors, qu'est-ce que cela a à voir avec le développement Android? Eh bien, à chaque nouvelle version du SDK Android, des classes, des interfaces, des méthodes, etc. sont ajoutées, mises à jour et (moins fréquemment) supprimées. Cependant, les développeurs Android souhaitent souvent cibler des appareils exécutant différentes versions d'Android avec un simple package d'application. Pour ce faire, les développeurs Android peuvent utiliser des techniques de réflexion pour déterminer, au moment de l'exécution, si une classe ou une méthode spécifique est disponible avant d'essayer de l'utiliser. Cela permet au développeur de tirer parti des nouvelles API, le cas échéant, tout en prenant en charge les appareils plus anciens, le tout dans la même application..
Les classes Java sont représentées à l'exécution à l'aide de la classe Class (java.lang.Class). Cette classe fournit le point de départ pour toutes les API de réflexion. Dans cette classe, vous trouverez de nombreuses méthodes pour inspecter différents aspects d'une classe, tels que ses champs, ses constructeurs, ses méthodes, ses autorisations, etc. Vous pouvez également utiliser la méthode de classe appelée forName () pour charger une classe non primitive (par exemple, pas int, mais Integer) par son nom de manière dynamique au moment de l'exécution, au lieu de la compilation:
String sClassName = "android.app.NotificationManager"; try Class classToInvestigate = Class.forName (sClassName); // Fait dynamiquement des choses avec cette classe // Liste des constructeurs, des champs, des méthodes, etc. catch (ClassNotFoundException e) // Classe non trouvée! catch (Exception e) // exception inconnue
La classe (dans ce cas, NotificationManager) n'a pas besoin d'avoir l'instruction d'importation correspondante dans votre code; vous ne compilez pas cette classe dans votre application. Au lieu de cela, le chargeur de classes chargera la classe de manière dynamique au moment de l'exécution, si possible. Vous pouvez ensuite inspecter cet objet de classe et utiliser les techniques de réflexion décrites dans la suite de ce didacticiel..
Vous pouvez inspecter les constructeurs disponibles dans une classe donnée. Pour obtenir uniquement les constructeurs accessibles au public, utilisez getConstructors (). Toutefois, si vous souhaitez inspecter les méthodes spécifiquement déclarées dans la classe, qu'elles soient publiques ou non, utilisez getDeclaredConstructors () à la place. Les deux méthodes renvoient un tableau d'objets Constructor (java.lang.reflect.Constructor).
Par exemple, le code suivant parcourt les constructeurs déclarés d'une classe:
Constructeur [] aClassConstructors = classToInvestigate.getDeclaredConstructors (); for (constructeur c: aClassConstructors) // A trouvé un constructeur c
Une fois que vous avez un objet Constructeur valide, vous pouvez inspecter ses paramètres et même déclarer une nouvelle instance de la classe à l'aide de ce constructeur avec la méthode newInstance ()..
Vous pouvez inspecter les champs (ou attributs) disponibles dans une classe donnée. Pour obtenir uniquement les méthodes accessibles au public, y compris les champs hérités, utilisez getFields (). Toutefois, si vous souhaitez inspecter les champs spécifiquement déclarés au sein de la classe (qu'ils ne soient pas hérités), qu'ils soient publics ou non, utilisez getDeclaredFields () à la place. Les deux méthodes renvoient un tableau d'objets Field (java.lang.reflect.Field)..
Par exemple, le code suivant parcourt les champs déclarés d'une classe:
Field [] aClassFields = classToInvestigate.getDeclaredFields (); for (Champ f: aClassFields) // Trouvé un champ f
Vous pouvez également rechercher un champ public spécifique par son nom à l'aide de la méthode getField (). Par exemple, pour vérifier le champ EXTRA_CHANGED_PACKAGE_LIST de la classe Intent (ajouté dans l'API de niveau 8 ou Android 2.2), vous pouvez utiliser:
String sClassName = "android.content.Intent"; try Class classToInvestigate = Class.forName (sClassName); String strNewFieldName = "EXTRA_CHANGED_PACKAGE_LIST"; Champ newIn22 = classToInvestigate.getField (strNewFieldName); catch (ClassNotFoundException e) // Classe non trouvée catch (NoSuchFieldException e) // Le champ n'existe pas, nous sommes probablement sous Android 2.1 ou plus ancien // fournissons une fonctionnalité alternative pour prendre en charge des appareils plus anciens catch (SecurityException e) // Accès refusé! catch (Exception e) // exception inconnue
Une fois que vous avez un objet Field valide, vous pouvez obtenir son nom à l'aide de la méthode toGenericString (). Si vous disposez des autorisations appropriées, vous pouvez également accéder à la valeur de ce champ de classe à l'aide des méthodes get () et set () appropriées..
Vous pouvez inspecter les méthodes disponibles dans une classe donnée. Pour obtenir uniquement les méthodes accessibles au public, y compris les méthodes héritées, utilisez getMethods (). Toutefois, si vous souhaitez inspecter les méthodes spécifiquement déclarées dans la classe (sans celles héritées), qu'elles soient publiques ou non, utilisez getDeclaredMethods () à la place. Les deux méthodes renvoient un tableau d'objets Method (java.lang.reflect.Method)..
Par exemple, le code suivant parcourt les méthodes déclarées d'une classe:
Méthode [] aClassMethods = classToInvestigate.getDeclaredMethods (); for (Méthode m: aClassMethods) // A trouvé une méthode m
Une fois que vous avez un objet Method valide, vous pouvez obtenir son nom à l'aide de la méthode toGenericString (). Vous pouvez également examiner les paramètres utilisés par la méthode et les exceptions qu’elle peut générer. Enfin, si vous disposez des autorisations appropriées, vous pouvez également appeler la méthode à l'aide de la méthode invoke ()..
Vous pouvez inspecter les classes internes définies dans une classe à l'aide de la méthode getDeclaredClasses (). Cette méthode renverra un tableau d'objets Class (java.lang.class) déclarés dans la classe parente. Ces classes peuvent ensuite être inspectées comme n'importe quelle autre.
Vous pouvez également examiner les indicateurs et les paramètres de sécurité, appelés modificateurs, associés à une classe, un champ ou une méthode donnés à l'aide de la méthode getModifiers (). Les modificateurs intéressants incluent si le composant est public, privé, protégé, abstrait, final ou statique (entre autres).
Par exemple, le code suivant vérifie les modificateurs de sécurité d'une classe:
int autorisations = classToInvestigate.getModifiers (); if (Modifier.isPublic (autorisations)) // La classe est publique if (Modifier.isProtected (autorisations)) // La classe est protégée if (Modifier.isPrivate (autorisations)) // La classe est privée
Gardez à l'esprit que vous ne pouvez pas accéder ou invoquer de manière dynamique une classe, une méthode ou un champ en utilisant une réflexion à laquelle vous ne seriez normalement pas en mesure d'accéder au moment de la compilation. En d'autres termes, la sécurité de classe normale est toujours appliquée au moment de l'exécution.
Vous pouvez également inspecter les métadonnées appelées annotations associées à une classe, un champ ou une méthode donnés à l'aide de la méthode getAnnotations (). Les métadonnées intéressantes associées à une classe peuvent inclure des informations sur la dépréciation, les avertissements et les remplacements, entre autres.
Par exemple, le code suivant vérifie les métadonnées disponibles pour la classe AbsoluteLayout. Depuis que cette classe est obsolète dans Android 1.5, l'une des annotations renvoyées est @ java.lang.Deprecated () lorsque ce code est exécuté sur Android 2.2:
String sClassName = "android.widget.AbsoluteLayout"; try Class classToInvestigate = Class.forName (sClassName); Annotation [] aAnnotations = classToInvestigate.getDeclaredAnnotations (); for (Annotation a: aAnnotations) // Vous avez trouvé une annotation, utilisez a.toString () pour l'imprimer catch (ClassNotFoundException e) // Classe non trouvée! catch (Exception e) // Gestion des exceptions inconnues!
De même, vous pouvez simplement vérifier l’existence d’une annotation spécifique, telle que dépréciation, par son type:
if (classToInvestigate.isAnnotationPresent (java.lang.Deprecated.class) == true) // La classe est obsolète!
Vous pouvez également utiliser la réflexion pour faciliter le débogage. Par exemple, vous voudrez peut-être utiliser le classe mot-clé pour accéder aux données de classe sous-jacentes pour un type donné:
import android.app.Activity;… String strClassName = Activity.class.getName (); // android.app.Activity
Vous pouvez également obtenir des informations de classe à partir d'une instance de variable à l'aide de la méthode getClass () de la classe Object (qui est donc héritée de toutes les classes en Java):
String silly = "Chaîne idiote!"; Classe someKindOfClass = silly.getClass (); String strSillyClassName = someKindOfClass.getName (); // java.lang.String
Si vous voulez vérifier la classe d'une variable, utiliser instanceof est plus approprié. Voir le tutoriel précédent sur instanceof pour plus de détails.
De même, vous pouvez utiliser la méthode getClass () avec le mot-clé this pour vérifier le nom de la classe dans laquelle vous vous trouvez et inclure ces informations dans le cadre de la journalisation du débogage dans LogCat:
String strCurrentClass = this.getClass (). GetName (); // par exemple. le journal d'activité actuel.v (strCurrentClass, "La balise de débogage est la classe actuelle");
Comme vous l'avez vu, la réflexion peut être très utile, notamment lorsque vous ne savez pas si une classe ou une méthode spécifique est disponible au moment de la compilation. La réflexion présente toutefois certains inconvénients, notamment une performance réduite et la perte des pratiques de frappe stricte et de codage sécurisé appliquées au moment de la compilation. Il est préférable d'utiliser la réflexion avec parcimonie, mais utilisez-la au besoin..
Reflection est un outil puissant que les développeurs Java peuvent utiliser pour explorer les packages et les API par programmation lors de l'exécution. Les opérations de réflexion ont un coût, mais elles offrent au développeur la flexibilité parfois indispensable pour mener à bien son travail. Les développeurs Android utilisent fréquemment ces techniques de réflexion simples pour tester la disponibilité de classes, interfaces, méthodes et champs spécifiques lors de l'exécution, leur permettant de prendre en charge différentes versions..
Les développeurs mobiles Lauren Darcey et Shane Conder ont co-écrit plusieurs livres sur le développement Android: un livre de programmation en profondeur intitulé Développement d'applications sans fil Android et Sams TeachYourself Développement d'applications Android en 24 heures. Lorsqu'ils n'écrivent pas, ils passent leur temps à développer des logiciels mobiles dans leur entreprise et à fournir des services de conseil. Vous pouvez les contacter par courrier électronique à l'adresse [email protected], via leur blog à l'adresse androidbook.blogspot.com et sur Twitter @androidwireless..