Bonjour.
Il est nécessaire de transférer les données reçues via UART vers Activity. Cela peut être fait en créant un thread dans l'activité dans lequel organiser une boucle while (! IsInterrupted ()) et lire les données à partir du tampon UART. Après cela, en appelant le thread d'interface utilisateur de l'activité - MainActivity.this.runOnUiThread (new Runnable (), effectuez les actions nécessaires avec cette activité. Mais si nous appelons d'autres activités à partir de l'activité principale, le fil organisé ne permet pas de transférer des données vers l'activité nouvellement créée. Si je Je comprends correctement que pour que les données du flux soient transférées vers une activité, le flux doit être créé non pas dans l'activité, mais dans le service.
Question: les données sont arrivées via UART, dans un flux (qui est créé dans Servce), il est nécessaire de transférer des données vers l'activité, qui est maintenant active, comment cela peut-il être fait et est-ce réellement fait?
1 réponse
Créez un gestionnaire dans chaque activité. Dans la méthode onResume () de cette activité, bindService (). Là, l'un des paramètres est l'interface ServiceConnection. Implémentez-le au moins avec la même activité. Implémentez la méthode onServiceConnected () dedans. Dans ce rappel, le service lui-même est l'un des paramètres. Appelez donc ce service votre propre méthode setHandler (). Passez-y le gestionnaire qui est dans l'activité actuelle. Mais envoyez les données entrantes via UART au service sur ce gestionnaire. À propos, Handler s'exécute traditionnellement sur le thread principal, vous n'aurez donc pas besoin de runOnUiThread pour s'exécuter.
L'application ne se compose pas toujours d'un seul écran. Par exemple, nous avons créé un programme très utile et l'utilisateur veut savoir qui est l'auteur. Il clique sur le bouton "A propos du programme" et accède à un nouvel écran, où il y a des informations utiles sur la version du programme, l'auteur, l'adresse du site, le nombre de chats de l'auteur, etc. Considérez un écran d'activité comme une page Web avec un lien vers une autre page. Si vous regardez le code dans le fichier MainActivity.java des leçons précédentes, vous verrez que notre classe Activité principale s'applique également à Activité (ou ses héritiers) ou, plus précisément, hérité de lui.
La classe publique MainActivity étend AppCompatActivity
Comme vous pouvez le deviner, nous devrions créer une nouvelle classe, qui pourrait ressembler à Activité principale puis basculez-y lorsque vous appuyez sur le bouton.
Pour l'expérience, nous allons reprendre le programme de la première leçon et utiliser un bouton pour les expériences (ou créer un nouveau projet avec un bouton à l'écran). Ensuite, créons un nouveau formulaire pour afficher des informations utiles. Par exemple, montrons à l'utilisateur ce que fait le chat lorsqu'il marche à gauche et à droite. D'accord, c'est une information très importante qui donne un indice sur l'Univers.
Nous allons créer une nouvelle activité manuellement, bien que le studio dispose de modèles prêts à l'emploi. Mais il n'y a rien de compliqué et pour mieux comprendre il est utile de tout faire à la main.
Créer un nouveau fichier de balisage XML activity_about.xml dans le dossier res / layout... Faites un clic droit sur le dossier disposition et sélectionnez dans le menu contextuel Nouveau | Fichier de ressources de mise en page... Une boîte de dialogue apparaîtra. Dans le premier champ, saisissez le nom du fichier activity_about... Dans le second, vous devez entrer l'élément racine. Par défaut, il y a ContrainteMise en page... Effacez le texte et entrez ScrollView... Il suffit de saisir quelques caractères pour que le studio propose des options prêtes à l'emploi, vous pouvez immédiatement appuyer sur Entrée, sans attendre la saisie complète du mot:
Nous obtiendrons le blanc correspondant, dans lequel nous insérerons l'élément Affichage.
Les informations seront extraites des ressources, à savoir d'une ressource chaîne about_text... Maintenant, il est surligné en rouge, signalant le manque d'informations. Tu pourrais appuyer Alt + Entrée et entrez le texte dans la boîte de dialogue. Mais pour notre exemple, cette méthode ne fonctionnera pas, puisque notre texte sera multi-lignes, en utilisant des caractères de contrôle. Alors faisons les choses différemment. Ouvrons le fichier res / values \u200b\u200b/ strings.xml et saisissez manuellement le texte suivant:
Nous avons utilisé les balises de formatage de texte HTML les plus simples comme , , ... Pour notre exemple, il suffit de mettre en évidence en gras les mots qui font référence au chat et au sens du mouvement. Pour transférer du texte sur une nouvelle ligne, utilisez les symboles \\ n... Ajoutons une autre ressource de chaîne pour le titre du nouvel écran:
Nous avons compris le balisage. Ensuite, vous devez créer une classe pour la fenêtre AboutActivity.java... Choisissez dans le menu Fichier | Nouveau | Classe Java et remplissez les champs obligatoires. Dans un premier temps, il suffit d'indiquer uniquement le nom. Traitez ensuite d'autres domaines.
Obtenons un blanc.
La classe est maintenant presque vide. Ajoutons le code manuellement. La classe doit hériter de la classe abstraite Activité ou ses proches comme FragmentActivité, AppCompatActivity etc. Nous ajoutons étend l'activité... La classe d'activité doit avoir une méthode onCreate ()... Nous plaçons le curseur de la souris dans la classe et sélectionnons dans le menu Code | Remplacer les méthodes (Ctrl + O). Dans la boîte de dialogue, nous recherchons la classe souhaitée, vous pouvez taper les premiers caractères du clavier pour recherche rapide... Dans la méthode créée, vous devez appeler la méthode setContentView ()qui chargera le balisage préparé sur l'écran. Nous aurons cette option.
Package ru.alexanderklimov.helloworld; import android.app.Activity; import android.os.Bundle; / ** * Créé par Alexander Klimov le 01.12.2014. * / classe publique AboutActivity s'étend l'activité (@Override protected void onCreate (Bundle savedInstanceState) (super.onCreate (savedInstanceState); setContentView (R.layout.activity_about);))
Maintenant, la chose la plus importante commence. Notre tâche consiste à accéder à un nouvel écran lorsque vous cliquez sur le bouton du premier écran. Retourner en classe Activité principale... Écrivons un gestionnaire de clic de bouton:
Public void onClick (Afficher la vue) (Intent intent \u003d new Intent (MainActivity.this, AboutActivity.class); startActivity (intent);)
Ici, j'ai utilisé la méthode de gestion des clics de bouton que j'ai décrite dans la leçon.
Pour démarrer un nouvel écran, vous devez créer une instance de la classe Intention et spécifiez la classe actuelle dans le premier paramètre, et la classe pour la transition dans le second, nous avons ceci À propos de l'activité... Après cela, la méthode est appelée startActivity ()qui lance un nouvel écran.
Si vous essayez maintenant de tester l'application dans l'émulateur, vous recevrez un message d'erreur. Qu'avons-nous fait de mal? Nous avons manqué une étape importante. Vous devez en enregistrer un nouveau Activité dans le manifeste AndroidManifest.xml... Trouvez ce fichier dans votre projet et double-cliquez dessus. La fenêtre d'édition de fichier s'ouvre. Ajouter un nouveau tag
Ainsi, la ressource de chaîne s'est avérée utile about_title... Lancez l'application, cliquez sur le bouton et ouvrez la fenêtre À propos du programme... Ainsi, nous avons appris à créer une nouvelle fenêtre et à l'appeler en un clic. Et nous avons à notre disposition un programme méga-pratique - maintenant il y aura toujours un indice à portée de main de ce que fait le chat quand il va vers la gauche.
Encore une fois, j'attire votre attention sur le fait que la deuxième classe d'activité créée doit hériter de la classe Activité ou similaire ( ListActivity et autres), avoir un fichier de balisage XML (si nécessaire) et être écrit dans le manifeste.
Après avoir appelé la méthode startActivity () une nouvelle activité commencera (dans ce cas À propos de l'activité), il deviendra visible et se déplacera vers le haut de la pile contenant les composants en cours d'exécution. Lors de l'appel de la méthode terminer () à partir d'une nouvelle activité (ou lorsqu'une touche de retour forcé est enfoncée), elle sera fermée et supprimée de la pile. Le développeur peut également accéder à l'activité précédente (ou à toute autre) en utilisant la même méthode. startActivity ().
Comment créer un troisième écran - un moyen pour les paresseux
Les programmeurs, comme les chats, sont des créatures paresseuses. Rappelez-vous toujours que pour l'activité, vous devez créer un balisage et une classe qui hérite de Activité, puis n'oubliez pas d'enregistrer la classe dans le manifeste - eh bien, nafig.
Dans ce cas, sélectionnez dans le menu Fichier | Nouveau | Activité | Activité de base (ou un autre modèle). Ensuite, la fenêtre familière pour créer une nouvelle activité apparaîtra. Nous remplissons les champs obligatoires.
Cliquez sur le bouton terminer et l'activité sera prête. Pour vérifier cela, ouvrez votre fichier manifeste et recherchez une nouvelle entrée. Je ne parle pas de fichiers de classe et de balisage, ils apparaîtront devant vous.
Ajoutez vous-même un nouveau bouton sur l'écran principal de l'activité et écrivez le code pour accéder à l'activité créée.
Dans un premier temps, je vous conseillerais de créer manuellement tous les composants nécessaires à une nouvelle activité afin de comprendre la relation entre classe, balisage et manifeste. Et lorsque vous mettez la main dessus, vous pouvez utiliser l'assistant de création d'activité pour accélérer votre travail.
Transférer des données entre les activités
Nous avons utilisé l'exemple le plus simple pour appeler un autre écran d'activité. Parfois, il est nécessaire non seulement d'appeler un nouvel écran, mais également d'y transférer des données. Par exemple, nom d'utilisateur. Dans ce cas, vous devez utiliser une zone spéciale extraDataque la classe a Intention.
Région extraData est une liste de paires valeur cléqui est transmis avec l'intention. Les chaînes sont utilisées comme clés, et pour les valeurs, vous pouvez utiliser tous les types de données primitifs, tableaux de primitives, objets de classe Paquet et etc.
Pour transférer des données vers une autre activité, utilisez la méthode putExtra ():
Intent.putExtra ("Clé", "Valeur");
L'activité de réception doit appeler une méthode appropriée: getIntExtra (), getStringExtra () etc.:
Int count \u003d getIntent (). GetIntExtra ("nom", 0);
Refaisons l'exemple précédent. Nous avons déjà trois activités. La première activité aura deux champs de texte et un bouton. L'apparence peut être la suivante:
La deuxième activité SecondActivity installer l'élément Affichage, dans lequel nous afficherons le texte reçu de la première activité. Écrivons le code suivant pour la méthode onCreate () à la deuxième activité.
@Override protected void onCreate (Bundle savedInstanceState) (super.onCreate (savedInstanceState); setContentView (R.layout.activity_second); String user \u003d "Live"; String gift \u003d "donut hole"; TextView infoTextView \u003d (TextView) findViewById R.id.textViewInfo); infoTextView.setText (utilisateur + ", on vous a donné" + cadeau);)
Si nous exécutons le programme maintenant et appelons simplement la deuxième fenêtre, comme décrit dans la première partie de l'article, nous verrons l'étiquette par défaut ZHYVotnoe, on vous a donné un trou de beignet... D'accord, c'est plutôt ennuyeux de recevoir de tels messages.
Nous réparons la situation. Ajoutez le code de la première activité:
Public void onClick (Affichage de la vue) (EditText userEditText \u003d (EditText) findViewById (R.id.editTextUser); EditText giftEditText \u003d (EditText) findViewById (R.id.editTextGift); Intent intent \u003d new Intent (MainActivity) class); // poussez le texte du premier champ de texte dans la clé de nom d'utilisateur intent.putExtra ("username", userEditText.getText (). toString ()); // poussez le texte du deuxième champ de texte dans la clé de cadeau intent.putExtra ("cadeau ", giftEditText.getText (). toString ()); startActivity (intent);)
Nous avons placé un objet dans un conteneur spécial Intention deux clés avec des valeurs tirées des champs de texte. Lorsque l'utilisateur saisit des données dans les champs de texte, il ira dans ce conteneur et sera transféré vers la deuxième activité.
La deuxième activité devrait être prête à recevoir des messages chaleureux comme suit (en gras).
// Valeurs par défaut String user \u003d "Live"; String gift \u003d "trou de beignet"; user \u003d getIntent (). getExtras (). getString ("nom d'utilisateur"); cadeau \u003d getIntent (). getExtras (). getString ("cadeau"); TextView infoTextView \u003d (TextView) findViewById (R.id.textViewInfo); infoTextView.setText (utilisateur + ", vous avez reçu" + cadeau);
Maintenant, le message ne semble pas si offensant, mais même agréable pour certains. Dans les exemples complexes, il est souhaitable d'ajouter une validation lors du traitement des données. Il y a des situations où vous démarrez la deuxième activité avec des données vides comme nulce qui peut planter l'application.
Dans notre cas, nous savons que nous attendons une valeur de chaîne, donc le code peut être réécrit comme ceci:
Intent intent \u003d getIntent (); user \u003d intent.getStringExtra ("nom d'utilisateur");
Utilisateur \u003d getIntent (). GetStringExtra ("nom d'utilisateur");
Le programme a un inconvénient - il n'est pas clair de qui nous recevons les salutations. Tout singe bien élevé n'acceptera pas de cadeau d'une source anonyme. Ainsi, comme devoir à la maison, ajoutez un autre champ de texte pour saisir le nom de l'utilisateur qui envoie le message.
Google recommande d'utiliser le format suivant pour les clés: le nom de votre package comme préfixe, suivi de la clé elle-même. Dans ce cas, vous pouvez être sûr que la clé est unique lors de l'interaction avec d'autres applications. Quelque chose comme ça:
Public final static String USER \u003d "ru.alexanderklimov.myapp.USER";
Qui a encadré le chat Vaska - nous récupérons le résultat
Il ne suffit pas toujours de simplement transmettre des données à une autre activité. Parfois, vous souhaitez récupérer des informations sur une autre activité lorsqu'elle est fermée. Si auparavant nous avons utilisé la méthode startActivity (intention d'intention), alors il y a une méthode connexe startActivityForResult (Intent intent, int RequestCode)... La différence entre les méthodes est le paramètre supplémentaire Code requis... Il s'agit essentiellement d'un entier que vous pouvez créer vous-même. Il est nécessaire pour distinguer de qui provient le résultat. Disons que vous avez cinq écrans supplémentaires et que vous leur attribuez des valeurs de 1 à 5, et à partir de ce code, vous pouvez déterminer le résultat que vous devez traiter. Vous pouvez utiliser la valeur -1, alors ce sera la même chose que l'appel de la méthode startActivity (), c'est à dire. nous n'obtenons aucun résultat.
Si vous utilisez la méthode startActivityForResult (), alors vous devez remplacer la méthode dans le code pour recevoir le résultat onActivityResult () et traitez le résultat. Confus? Prenons un exemple.
Disons que vous êtes un détective. Il y avait des informations selon lesquelles deux morceaux de saucisse et d'autres produits avaient été volés sur la table d'une personne influente dans un restaurant. Les soupçons sont tombés sur trois suspects - un corbeau, un putain de toutou et un chat Vaska.
L'un des visiteurs a fourni une série de photos de son iPhone de ponton:
Il y a aussi le témoignage d'un autre témoin: Et Vaska écoute, mais mange.
Créer un nouveau projet Sherlock avec deux activités. Le premier écran aura un bouton pour passer au deuxième écran et une étiquette de texte qui affichera le nom du voleur.
Le deuxième écran aura un groupe de boutons radio:
Puisque nous attendons une réponse du deuxième écran, nous devons utiliser la méthode startActivityForResult () sur le premier écran dans lequel on passe la variable CHOOSE_THIEF comme paramètre Code requis.
Private final statique int CHOOSE_THIEF \u003d 0; public void onClick (View v) (Intent questionIntent \u003d new Intent (MainActivity.this, ChooseActivity.class); startActivityForResult (questionIntent, CHOOSE_THIEF);)
Jetez un œil au code. Lorsque nous cliquons sur le bouton, nous allons travailler avec le deuxième écran ChoisissezActivité et lancez le deuxième écran en attendant le résultat.
Accédez au deuxième écran et écrivez le code de la deuxième activité.
Chaîne statique finale publique THIEF \u003d "ru.alexanderklimov.sherlock.THIEF"; public void onRadioClick (View v) (Intent answerIntent \u003d new Intent (); switch (v.getId ()) (case R.id.radioDog: answerIntent.putExtra (THIEF, "Fucking doggie"); break; case R.id .radioCrow: answerIntent.putExtra (THIEF, "Crow"); break; case R.id.radioCat: answerIntent.putExtra (THIEF, "Przewalski's horse"); break; default: break;) setResult (RESULT_OK, answerIntent); finish ();)
Tout est simple ici, quand le détective choisit le nom du criminel, puis à travers la méthode putExtra () on passe le nom de la clé et sa valeur.
Pour plus de commodité, après sélection, nous fermons immédiatement la deuxième fenêtre et passons la valeur avant de fermer RESULT_OKpour indiquer clairement que le choix a été fait. Si l'utilisateur ferme l'écran via le bouton Retour, la valeur sera transmise RESULT_CANCELED.
Méthode setResult () prend deux paramètres: le code du résultat et le résultat lui-même, représenté comme une intention. Le code résultant vous indique le résultat avec lequel l'activité s'est terminée, en règle générale, il s'agit soit Activité.RESULT_OKou Activité.RESULT_CANCELED... Dans certains cas, vous devrez peut-être utiliser votre propre code de retour pour gérer les variations spécifiques à votre application. Méthode setResult () prend en charge toute valeur entière.
Si vous passez des données explicitement via un bouton, alors ce serait bien d'ajouter une méthode terminer ()pour fermer la deuxième activité comme inutile. Si la transition se produit via le bouton Retour, cela n'est pas nécessaire.
Si l'activité a été fermée par l'utilisateur lorsque le bouton de retour matériel a été enfoncé, ou si la méthode terminer () a été appelé avant la méthode setResult (), le code résultant sera défini sur RESULT_CANCELEDet l'intention renvoyée affichera la valeur nul.
Nous revenons au premier écran. Le premier écran attend une réponse du deuxième écran, vous devez donc ajouter la méthode au code onActivityResult ().
@Override protected void onActivityResult (int requestCode, int resultCode, Intent data) (super.onActivityResult (requestCode, resultCode, data); TextView infoTextView \u003d (TextView) findViewById (R.id.textViewInfo); if (requestCode \u003d\u003d CHOOSE_THIEF) ( if (resultCode \u003d\u003d RESULT_OK) (String thiefname \u003d data.getStringExtra (ChooseActivity.THIEF); infoTextView.setText (thiefname);) else (infoTextView.setText (""); // efface le texte)))
La méthode attend des données entrantes avec du code CHOOSE_THIEF, et si de telles données arrivent, extrait la valeur de la clé ChooseActivity.THIEF en utilisant la méthode getStringExtra... Nous sortons la valeur résultante dans Affichage (variable infoTextView). Si nous retournons à l'écran via le bouton Retour, nous effaçons simplement le texte.
Lorsque l'activité enfant est fermée à l'intérieur du composant parent, le gestionnaire est déclenché onActivityResult ()... Gestionnaire onActivityResult () prend plusieurs paramètres.
- Code requis. Code qui a été utilisé pour démarrer une activité qui renvoie un résultat
- Code de résultat. Le code de résultat défini par l'activité enfant qui indique comment l'activité s'est terminée. Il peut s'agir de n'importe quelle valeur entière, mais généralement soit Activité.RESULT_OKou Activité.RESULT_CANCELED
- Les données. L'intention utilisée pour empaqueter les données renvoyées. En fonction de l'objectif de l'activité enfant, elle peut inclure un chemin URI représentant l'élément de contenu sélectionné. Alternativement (ou en plus) l'activité enfant peut renvoyer des informations sous forme de valeurs simples, regroupées dans un paramètre d'intention suppléments
Si l'activité enfant s'est terminée de manière inattendue ou si aucun code de résultat n'a été spécifié avant de la fermer, ce paramètre deviendra Activité.RESULT_CANCELED.
Nous lançons le projet, cliquons sur le bouton et passons au deuxième écran. Là, nous choisissons l'une des options. Si vous sélectionnez le corbeau, l'écran se fermera et le nom du criminel sera affiché sur le premier écran. Si vous sélectionnez un chien, son nom sera affiché.
Au fait, si vous sélectionnez un chat, son nom ne sera pas affiché! Vérifiez-le et voyez par vous-même. Vous demanderez pourquoi? Watson élémentaire! L'auteur n'a pas tenu compte d'un détail important. Le restaurant était surveillé avec des caméras vidéo et les images montraient qui avait effectivement volé la saucisse et dressé le chat. Vaska, tiens bon!
P.S. Si au début quelque chose semblait incompréhensible, alors avec la pratique, beaucoup deviendra clair. Le transfert de données entre les écrans est courant dans les applications et vous étudierez l'exemple encore et encore.
P.P.S. Le meilleur poisson est la saucisse. Connaissant cette faiblesse, il n'a pas été difficile de remplacer le chat.
Utiliser des filtres
Dans l'article, j'ai montré un moyen courant de passer à une autre activité, lorsque dans la méthode startActivity () indique la classe actuelle et la classe de la transition. Au fait, la classe d'activité n'a pas à faire partie de votre application. Si vous connaissez le nom de la classe d'une autre application, vous pouvez y accéder. Mais vous pouvez passer à une autre activité d'une manière différente.
En pratique, c'est moins courant, mais cela peut être utile. Disons que vous avez déjà une deuxième activité. Ajoutez-y un filtre spécial dans le manifeste:
Et nous lançons la deuxième activité en cliquant sur le bouton de cette manière.
Public void onClick (View view) (startActivity (new Intent ("ru.alexanderklimov.testapplication.SecondActivity"));)
Remplaçons la longue chaîne par une constante.
Public static final String ACTION_SECOND_ACTIVITY \u003d "ru.alexanderklimov.testapplication.SecondActivity"; public void onClick (View view) (startActivity (new Intent (ACTION_SECOND_ACTIVITY));)
Alors, qu'avons-nous fait. Pour la deuxième activité, nous avons ajouté un filtre et spécifié un nom pour action dans l'attribut android: nom... Pour plus de commodité, je mets simplement le nom complet de l'activité avec le nom du package. Constructeur de classe Intention a plusieurs versions surchargées. Dans une version, vous pouvez spécifier une chaîne pour l'action. Nous avons indiqué notre action créée, qui est enregistrée dans la deuxième activité. Le système examine les manifestes de toutes les applications installées pendant le fonctionnement. Lors de la recherche d'une correspondance, le système trouve notre filtre et lance l'activité souhaitée.
D'autres activités peuvent être lancées selon le même principe. Jetez un œil à un exemple. Si vous copiez l'exemple pour vous-même et regardez la documentation pour android.provider.Settings.ACTION_AIRPLANE_MODE_SETTINGS, vous verrez que ce code correspond à la constante chaîne public static final java.lang.String ACTION_AIRPLANE_MODE_SETTINGS \u003d "android.settings.AIRPLANE_MODE_SETTINGS"... Comparez avec notre code. Vous pouvez supposer que l'activité des paramètres du mode hors ligne a cette ligne écrite dans le filtre.
Nom de la catégorie de filtre android.intent.category.DEFAULT indique au système de prendre l'action par défaut, qui consiste à démarrer l'activité. Il y a d'autres noms qui ne nous intéressent pas encore.
Et maintenant une question à remplir. Que se passe-t-il si vous créez une autre activité et spécifiez le même filtre que la deuxième activité? Regardons ça. Créez une troisième activité en vous-même et copiez-y le bloc avec le filtre de la deuxième activité.
Nous cliquons sur le bouton dans la première activité. Le système vous demandera de sélectionner l'option souhaitée.
Si vous sélectionnez l'élément TOUJOURS, vous n'aurez pas à choisir la prochaine fois. Pour réinitialiser la sélection, accédez aux propriétés de l'application dans Paramètres et recherchez le bouton Effacer les valeurs par défaut.
Exécuter une activité par son nom
Dans le constructeur Intention le deuxième paramètre est la classe. Mais supposons qu'il existe une sorte de base de données où les noms des activités sont spécifiés et que nous devons lancer l'activité nécessaire par son nom. Nous pouvons obtenir la classe elle-même en fonction de la variable de chaîne et démarrer l'activité.
Try (// Nom complet de la classe d'activité String activityName \u003d "ru.alexanderklimov.testapplication.SecondActivity"; // récupère l'objet Class Class> myClass \u003d Class.forName (activityName); Intent intent \u003d new Intent (this, myClass); startActivity (intention); ) catch (ClassNotFoundException e) (e.printStackTrace ();)
Dernière mise à jour: 03.04.2018
Un intent est utilisé pour transférer des données entre deux activités. Grâce à sa méthode putExtra (), vous pouvez ajouter une clé et sa valeur associée.
Par exemple, en passant de l'activité en cours à SecondActivity la chaîne "Hello World" avec la clé "hello":
// crée une intention pour lancer SecondActivity Intent intent \u003d new Intent (this, SecondActivity.class); // en passant un objet avec la clé "hello" et la valeur "Hello World" intent.putExtra ("hello", "Hello World"); // démarrer SecondActivity startActivity (intent);
Pour transférer des données, la méthode putExtra () est utilisée, qui vous permet de transférer des données des types les plus simples sous forme de valeur - String, int, float, double, long, short, byte, char, des tableaux de ces types ou un objet de l'interface Serializable.
Pour obtenir les données envoyées lors du chargement de SecondActivity, vous pouvez utiliser la méthode get (), qui reçoit la clé d'objet:
Arguments du bundle \u003d getIntent (). GetExtras (); String name \u003d arguments.get ("bonjour"). ToString (); // Bonjour le monde
Selon le type de données envoyées, lorsque nous les recevons, nous pouvons utiliser un certain nombre de méthodes sur l'objet Bundle. Tous prennent la clé d'objet comme paramètre. Les principaux sont:
get (): une méthode générique qui renvoie une valeur de type Object. En conséquence, le champ de réception, cette valeur doit être convertie dans le type souhaité
getString (): renvoie un objet String
getInt (): renvoie une valeur int
getByte (): renvoie une valeur d'octet
getChar (): renvoie une valeur char
getShort (): renvoie une valeur courte
getLong (): renvoie une valeur longue
getFloat (): renvoie une valeur flottante
getDouble (): renvoie un double
getBoolean (): renvoie une valeur booléenne
getCharArray (): retourne un tableau d'objets char
getIntArray (): retourne un tableau d'objets int
getFloatArray (): renvoie un tableau d'objets flottants
getSerializable (): retourne un objet d'interface Serializable
Laissez-nous définir deux activités dans notre projet: MainActivity et SecondActivity.
Dans le code SecondActivity, nous définissons la réception des données:
Package com.example.eugene.serializeapp; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; classe publique SecondActivity prolonge AppCompatActivity (@Override protected void onCreate (Bundle savedInstanceState) (super.onCreate (savedInstanceState); TextView textView \u003d new TextView (ce); textView.setTextSize (20); textView.setPadding (16, 16, 16, 16 ); Bundle arguments \u003d getIntent (). GetExtras (); if (arguments! \u003d Null) (String name \u003d arguments.get ("name"). ToString (); String company \u003d arguments.getString ("company"); int price \u003d arguments.getInt ("price"); textView.setText ("Name:" + name + "\\ nCompany:" + company + "\\ nPrice:" + price);) setContentView (textView);))
Dans ce cas, dans SecondActivity, nous récupérons toutes les données de l'objet Bundle et les affichons dans le champ de texte TextView. On suppose que cette activité sera passée trois éléments - deux chaînes avec le nom des clés et la société et un numéro avec le prix de la clé.
Définissons maintenant le transfert des données vers SecondActivity. Par exemple, définissons l'interface suivante pour MainActivity dans le fichier activity_main.xml:
Il définit trois champs de texte pour la saisie des données et un bouton.
Dans la classe MainActivity, nous définissons le contenu suivant:
Package com.example.eugene.serializeapp; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.EditText; classe publique MainActivity extend AppCompatActivity (@Override protected void onCreate (Bundle savedInstanceState) (super.onCreate (savedInstanceState); setContentView (R.layout.activity_main);) public void onClick (View v) (final EditText nameText \u003d findViewById (R. .name); final EditText companyText \u003d findViewById (R.id.company); final EditText priceText \u003d findViewById (R.id.price); String name \u003d nameText.getText (). toString (); String company \u003d companyText.getText ( ) .toString (); int price \u003d Integer.parseInt (priceText.getText (). toString ()); Intent intent \u003d new Intent (this, SecondActivity.class); intent.putExtra ("name", name); intent. putExtra ("société", société); intent.putExtra ("prix", prix); startActivity (intention);))
Dans le gestionnaire de clic de bouton, nous récupérons les données entrées dans les champs de texte EditText et les transmettons à l'intention à l'aide de la méthode putExtra (). Ensuite, nous lançons SecondActivity.
En conséquence, lorsque vous cliquez sur le bouton, SecondActivity sera lancé, qui recevra certaines données saisies dans les champs de texte.
Transférer des objets complexes
Dans l'exemple ci-dessus, des données simples ont été transférées - des nombres, des chaînes. Mais nous pouvons également transférer des données plus complexes. Dans ce cas, le mécanisme de sérialisation est utilisé.
Par exemple, laissez-nous définir une classe Product dans notre projet:
Package com.example.eugene.serializeapp; import java.io.Serializable; classe publique Product implements Serializable (nom de chaîne privé; société de chaîne privée; prix int privé; produit public (nom de chaîne, société de chaîne, prix int) (this.name \u003d nom; this.company \u003d company; this.price \u003d price;) public String getName () (return name;) public void setName (String name) (this.name \u003d name;) public String getCompany () (return company;) public void setCompany (String company) (this.company \u003d company;) public int getPrice () (return price;) public void setPrice (int price) (this.price \u003d price;))
Il est à noter que cette classe implémente l'interface Serializable. Modifions maintenant le code de MainActivity:
Package com.example.eugene.serializeapp; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.EditText; classe publique MainActivity extend AppCompatActivity (@Override protected void onCreate (Bundle savedInstanceState) (super.onCreate (savedInstanceState); setContentView (R.layout.activity_main);) public void onClick (View v) (final EditText nameText \u003d findViewById (R. .name); final EditText companyText \u003d findViewById (R.id.company); final EditText priceText \u003d findViewById (R.id.price); String name \u003d nameText.getText (). toString (); String company \u003d companyText.getText ( ) .toString (); int price \u003d Integer.parseInt (priceText.getText (). toString ()); Product product \u003d new Product (nom, société, prix); Intent intent \u003d new Intent (this, SecondActivity.class); intent.putExtra (Product.class.getSimpleName (), produit); startActivity (intent);))
Désormais, au lieu de trois données dispersées, un seul objet Product est passé. Le résultat de la méthode Product.class.getSimpleName () est utilisé comme clé, qui renvoie essentiellement le nom de la classe.
Et changeons la classe SecondActivity:
Package com.example.eugene.serializeapp; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.widget.TextView; classe publique SecondActivity prolonge AppCompatActivity (@Override protected void onCreate (Bundle savedInstanceState) (super.onCreate (savedInstanceState); TextView textView \u003d new TextView (ce); textView.setTextSize (20); textView.setPadding (16, 16, 16, 16 ); Bundle arguments \u003d getIntent (). GetExtras (); produit final du produit; if (arguments! \u003d Null) (product \u003d (Product) arguments.getSerializable (Product.class.getSimpleName ()); textView.setText ("Nom: "+ product.getName () +" \\ nCompany: "+ product.getCompany () +" \\ nPrix: "+ String.valueOf (product.getPrice ()));) setContentView (textView);))
La méthode getSerializable () est utilisée pour obtenir les données car la classe Product implémente l'interface Serializable. De cette façon, nous pouvons passer un seul objet au lieu d'une collection de données disparates.
D'une manière ou d'une autre, j'avais pour tâche de transférer des données du service vers l'activité. J'ai commencé à chercher une solution dans le SDK standard, mais comme il n'y avait pas de temps, j'ai fait une mauvaise solution sous la forme d'utiliser une base de données. Mais la question était ouverte et après un certain temps, j'ai trouvé une manière plus correcte, qui se trouve dans le SDK - en utilisant les classes Message, Handler, Messenger.
Idée
Nous devons transférer des données d'une activité à l'autre et vice versa. Comment faisons-nous cela? Nous avons déjà tout ce dont nous avons besoin pour résoudre notre problème. Tout ce dont vous avez besoin est de lier le service à l'activité à l'aide de bindService, de passer les paramètres nécessaires et un peu de magie sous la forme d'utilisation des classes Message. Et la magie est d'utiliser des variables d'instance Message et en particulier replyTo. Nous avons besoin de cette variable pour pouvoir faire référence à l'instance Messanger du service depuis l'activation et dans le service à l'instance Messanger de l'activation. En fait, ce n'est pas si simple. Au moins pour mon esprit pas le plus doué. En partie, j'améliore simplement la documentation qui existe déjà - Services De plus, il existe un bon exemple sur StackOverflow. En tout cas, j'espère que l'article sera utile à au moins quelqu'un et je n'ai pas travaillé en vain.
Exemple
À titre d'exemple, nous allons implémenter un service qui augmentera et diminuera la valeur du compteur et renvoyer le résultat à l'activité, au TextView. Je vais omettre le code de mise en page, car il y a deux boutons et un champ de texte - tout est simple.
la mise en oeuvre
Je vais donner le code d'activation complet:
Classe publique MainActivity extend Activity (public static final String TAG \u003d "TestService"; TestServiceConnection testServConn; TextView testTxt; final Messenger messenger \u003d new Messenger (new IncomingHandler ()); Messenger toServiceMessenger; @Override public void onCreate (Bundle savedInstanceState) (super onCreate (savedInstanceState); setContentView (R.layout.activity_main); testTxt \u003d (TextView) findViewById (R.id.test_txt); bindService (new Intent (this, TestService.class), (testServConn \u003d new TestServiceConnection ()), Contexte .BIND_AUTO_CREATE);) @Override public void onDestroy () (super.onDestroy (); unbindService (testServConn);) public void countIncrClick (bouton Afficher) (Message msg \u003d Message.obtain (, TestService.COUNT_PLUS); msg.reply \u003d messenger; try (toServiceMessenger.send (msg);) catch (RemoteException e) (e.printStackTrace ();)) public void countDecrClick (bouton Afficher) (Message msg \u003d Message.obtain (, TestService.COUNT_MINUS); msg .répondre à \u003d messager; try (toServiceMessenger.send (msg);) catch (RemoteException e) (e.printStackTrace ();)) classe privée IncomingHandler extend Handler (@Override public void handleMessage (Message msg) (commutateur (msg.what) (case TestService. GET_COUNT: Log.d (TAG, "(activity) ... get count"); testTxt.setText ("" + msg.arg1); break;))) classe privée TestServiceConnection implémente ServiceConnection (@Override public void onServiceConnected (ComponentName name, IBinder service) (toServiceMessenger \u003d new Messenger (service); // envoyer la valeur initiale du compteur Message msg \u003d Message.obtain (, TestService.SET_COUNT); msg.replyTo \u003d messenger; msg.arg1 \u003d 0; // notre compteur try (toServiceMessenger.send (msg);) catch (RemoteException e) (e.printStackTrace ();)) @Override public void onServiceDisconnected (nom du composant) ()))
Laisse-moi expliquer. Lors de la création d'une activité, nous nous lions immédiatement au service, implémentons l'interface ServiceConnection et nous y envoyons un message au service "définir la valeur du compteur", en passant zéro et en créant toServiceMessanger, en passant l'interface IBinder au constructeur. Au fait, le service doit renvoyer cette instance, sinon ce sera NPE. Nous utilisons cette classe pour envoyer des messages au service. Et ici c'est magique - dans la variable replyTo nous sauvegardons notre autre instance Messenger - celle qui reçoit une réponse du serveur et c'est à travers lui que la communication avec l'activité se fera.
Pour recevoir un message du service, nous utilisons notre gestionnaire et cherchons simplement les variables dont nous avons besoin et faisons des actions sur elles. Par des clics sur les boutons (méthodes countIncrClick, countDecrClick), nous envoyons des requêtes au service, en indiquant l'action souhaitée dans la variable msg.what.
Package com.example.servicetest; import android.app.Service; import android.content. *; import android.os. *; import android.os.Process; import android.util.Log; classe publique TestService extend Service (public static final int COUNT_PLUS \u003d 1; public static final int COUNT_MINUS \u003d 2; public static final int SET_COUNT \u003d 0; public static final int GET_COUNT \u003d 3; int count \u003d 0; IncomingHandler inHandler; Messenger messanger; Messenger toActivityMessenger; @Override public void onCreate () (super.onCreate (); HandlerThread thread \u003d new HandlerThread ("ServiceStartArguments", Process.THREAD_PRIORITY_BACKGROUND); thread.start (); inHandler \u003d new IncomingHandoler (thread ). \u003d new Messenger (inHandler);) @Override public IBinder onBind (Intent arg0) (return messanger.getBinder ();) @Override public int onStartCommand (Intent intent, int flags, int startId) (return START_STICKY;) // gestionnaire de messages classe privée IncomingHandler extend Handler (public IncomingHandler (Looper looper) (super (looper);) @Override public void handleMessage (Message msg) (//super.handleMessage(msg); toActivityMess enger \u003d msg.replyTo; switch (msg.what) (case SET_COUNT: count \u003d msg.arg1; Log.d (MainActivity.TAG, "(service) ... set count"); break; case COUNT_PLUS: count ++; Log.d (MainActivity.TAG , "(service) ... count plus"); break; case COUNT_MINUS: Log.d (MainActivity.TAG, "(service) ... count minus"); count--; break;) // envoyer la valeur du compteur dans l'activité Message outMsg \u003d Message.obtain (inHandler, GET_COUNT); outMsg.arg1 \u003d nombre; outMsg.replyTo \u003d messanger; try (if (toActivityMessenger! \u003d null) toActivityMessenger.send (outMsg);) catch (RemoteException e) (e.printStackTrace ();))))
Le tout par analogie avec la logique de l'activité. Je ne sais même pas si j'ai besoin d'expliquer quelque chose. Le seul point est que j'envoie immédiatement une requête à l'activité dans handleMessage, en utilisant la variable magic replyTo et en tirant le Messenger souhaité ci-dessus. Et le deuxième point dont j'ai déjà parlé est:
@Override public IBinder onBind (Intent arg0) (return messanger.getBinder ();)
sans quoi tout tombera. C'est cette instance de l'interface qui sera transmise au ServiceConnection
Conclusion
En tout. Tel est l'exemple artificiel de l'interaction entre les activités et les services. Il me semble que c'est une interaction plutôt non triviale, même si cela peut sembler différent pour quelqu'un.
Questions, clarifications et ainsi de suite à titre personnel. Il peut y avoir des inexactitudes sur tous les aspects, alors n'hésitez pas à écrire et à corriger.
J'espère que l'article a été utile aux lecteurs.