Connexion, Téléchargement Et Parsulation De Ressources Internet

 À l'aide des API réseau d'Android, vous pouvez vous connecter à des points de terminaison de serveur distant, émettre des requêtes HTTP et traiter des résultats de serveur et des flux de données, notamment en extrayant et en traitant des données à l'aide d'un analyseur, tel que SAX, l'analyseur XML Pull ou le lecteur JSON. Les appareils mobiles modernes offrent un certain nombre de solutions pour accéder à Internet. En gros, Android fournit deux techniques de connexion pour la connectivité Internet, chacune étant automatiquement proposée à la couche d'application. Vous n'avez pas à indiquer quelle technologie utiliser pour établir une connexion Internet:

  • Mobile Internet—GPRS, EDGE, 3G, 4G, and LTE Internet access is available through carriers that offer mobile data.
  • Wi-Fi—Private and public Wi-Fi access points.

Si vous utilisez des ressources Internet dans votre application, n’oubliez pas que les connexions de données de vos utilisateurs dépendent de la technologie de communication à leur disposition. Les connexions EDGE et GSM sont notoirement à faible bande passante, alors qu'une connexion Wi-Fi peut ne pas être fiable dans un environnement mobile. Optimisez l'expérience utilisateur en minimisant toujours la quantité de données transmises et assurez-vous que votre application est suffisamment robuste pour gérer les pannes de réseau et les limitations de bande passante / latence. 
Pourquoi construire une application Internet native? Étant donné qu’un navigateur Web est disponible sur la plupart des appareils intelligents, vous pouvez vous demander s’il existe une quelconque raison de créer des applications Internet natives alors que vous pourriez créer une version Web. Alors que les navigateurs Web mobiles deviennent de plus en plus puissants, la création d’applications natives pour clients légers et lourds présente encore de nombreux avantages, au lieu de compter uniquement sur des solutions entièrement basées sur le Web: 

  • W Bande passante: les ressources statiques telles que les images, les mises en page et les sons peuvent coûter cher sur les appareils soumis à des contraintes de bande passante. En créant une application native, vous pouvez limiter les besoins en bande passante aux données modifiées.   
  • Availability Disponibilité hors ligne: avec une solution basée sur un navigateur, une connexion Internet fragmentée peut entraîner une disponibilité intermittente des applications. Une application native peut mettre en cache les données et les actions de l'utilisateur pour fournir autant de fonctionnalités que possible sans connexion en direct, et se synchroniser avec le nuage lorsqu'une connexion est rétablie. 
  • Latence et UX: en créant une application native, vous pouvez tirer parti d'une latence d'interaction utilisateur plus faible et vous assurer que l'expérience utilisateur est cohérente avec le système d'exploitation et les autres applications tierces et tierces.  
  • Réduction de la consommation de batterie: chaque fois que votre application ouvre une connexion à un serveur, la radio sans fil est activée (ou maintenue). Une application native peut regrouper ses connexions, réduisant ainsi le nombre de connexions initiées. Plus l'intervalle entre les demandes du réseau est long, plus la radio sans fil peut rester longue et l'impact sur la durée de vie de la batterie est faible.  
  • Features Fonctions natives: les appareils Android sont plus que de simples plates-formes pour exécuter un navigateur.Ils comprennent les services basés sur la localisation, les notifications, les widgets, les caméras, les radios Bluetooth, les services d'arrière-plan et les capteurs matériels. En créant une application native, vous pouvez combiner les données disponibles en ligne avec les fonctionnalités matérielles disponibles sur le périphérique pour offrir une expérience utilisateur plus riche.

 Connexion à une ressource Internet

 Avant de pouvoir accéder aux ressources Internet, vous devez ajouter un nœud INTERNET utilisations-permission à votre manifeste d'application, comme indiqué dans l'extrait de code XML suivant:

  1. < uses-permission android:name="android.permission.INTERNET"/ >

 Le Listing 7-1 montre le modèle de base pour ouvrir une connexion de données Internet et recevoir un flux de données à partir d'un flux de données. 

 

  1. try { URL url = new URL(myFeed);
  2. // Create a new HTTP URL connection
  3. URLConnection connection = url.openConnection();
  4. HttpURLConnection httpConnection = (HttpURLConnection) connection;
  5. int responseCode = httpConnection.getResponseCode();
  6. if (responseCode == HttpURLConnection.HTTP_OK) {
  7. InputStream in = httpConnection.getInputStream();
  8. processStream(in);
  9. }
  10. httpConnection.disconnect();
  11. }
  12. Log.e(TAG, "Malformed URL Exception.", e);
  13. }
  14. catch (IOException e) {
  15. Log.e(TAG, "IO Exception.", e);
  16. }

AVERTISSEMENT : Sous Android, toute tentative d'opération réseau sur le thread d'interface utilisateur principal provoquera une exception NetworkOnMainThreadException. Pour vous connecter à une ressource Internet, vous devez le faire à partir d'un thread en arrière-plan. La section suivante décrit une technique recommandée pour déplacer des opérations réseau vers des threads d'arrière-plan à l'aide d'une combinaison des classes View Model, Live Data et Asynchronous Task. Android comprend plusieurs classes pour vous aider à gérer les communications réseau. Ils sont disponibles dans le java.net.* and android.net.* packages.  


Opérations réseau sur les threads d'arrière-plan à l'aide de modèles de vue, de données Live et de tâches asynchrones

 Il est toujours recommandé d’effectuer des tâches qui prennent beaucoup de temps, telles que des opérations réseau sur un thread en arrière-plan. Cela garantit que vous ne bloquez pas le thread d'interface utilisateur, ce qui rendrait votre application silencieuse ou insensible. Sur Android, cette meilleure pratique est appliquée pour les opérations réseau via l'exception NetworkOnMainThreadException, qui est déclenchée chaque fois qu'une opération réseau est tentée sur le thread d'interface utilisateur principal.

 Remarque «Utilisation de l'arrière-plan», vous apprendrez un large éventail d'options pour déplacer des opérations vers des threads d'arrière-plan. Vous êtes également familiarisé avec les API conçues pour planifier efficacement les opérations réseau en arrière-plan, y compris le planificateur de travaux. Dans votre activité, vous pouvez créer et exécuter un nouveau thread, comme indiqué dans le code suivant. Lorsque vous êtes prêt à poster sur le thread d'interface utilisateur, appelez runOnUIThread et appliquez les modifications de votre interface utilisateur dans un autre Runnable: 

 

  1. Thread t = new Thread(new Runnable() {
  2. public void run() {
  3. // Perform Network operations and processing.
  4. final MyDataClass result = loadInBackground();
  5. // Synchronize with the UI thread to post changes.
  6. runOnUiThread(new Runnable() {
  7.  
  8. @Override
  9. public void run() {
  10. deliverResult(result);
  11. }
  12. });
  13. } }) ;
  14. t.start();

 Vous pouvez également tirer parti de la classe AsyncTask, qui encapsule ce processus pour vous. Une tâche async vous permet de définir une opération à exécuter en arrière-plan et fournit des gestionnaires d'événements vous permettant de surveiller la progression et d'afficher les résultats sur le thread d'interface graphique. Async Task gère la création, la gestion et la synchronisation des threads, ce qui vous permet de créer une tâche asynchrone comprenant un traitement à effectuer en arrière-plan et des mises à jour de l'interface utilisateur à effectuer à la fois pendant et après le traitement. Pour créer une nouvelle tâche asynchrone, étendez la classe AsyncTask en spécifiant les types de paramètre à utiliser, comme indiqué dans le code ci-dessous:

 

  1. private class MyAsyncTask extends AsyncTask<String,Integer,String> {
  2. @Override
  3. protected String doInBackground(String... parameter) {
  4. // Moved to a background thread.
  5. String result = "";
  6. int myProgress = 0;
  7. int inputLength = parameter[0].length();
  8. // Perform background processing task,update myProgress
  9. for (int i = 1; i <= inputLength; i++) {
  10. myProgress = i;
  11. result = result + parameter[0].charAt(inputLength-i);
  12. try {
  13. Thread.sleep(100);
  14. } catch (InterruptedException e) { }
  15. // Send progress to onProgressUpdate handler
  16. publishProgress(myProgress);
  17. }
  18. // Return the value to be passed to onPostExecute
  19. return result;
  20. }
  21. @Override
  22. protected void onProgressUpdate(Integer... progress) {
  23. // Synchronized to UI thread.
  24. // Update progress bar, Notification, or other UI elements
  25. }
  26. @Override
  27. protected void onPostExecute(String result) {
  28. // Synchronized to UI thread.
  29. // Report results via UI update, Dialog, or notifications
  30. }
  31. }

Après avoir implémenté une tâche asynchrone, exécutez-la en créant une nouvelle instance et en appelant la commande execute, en transmettant tous les paramètres requis: 

  1. String input = "redrum ... redrum"; new MyAsyncTask().execute(input);

 Chaque instance de tâche async ne peut être exécutée qu'une seule fois. Si vous tentez d'appeler une deuxième fois, une exception sera levée. Ces approches présentent plusieurs limitations importantes liées au cycle de vie d'une activité décrit au chapitre 3. Comme vous le savez, une activité (et ses fragments) peut être détruite et recréée chaque fois que la configuration de l'appareil change. En conséquence, un utilisateur qui fait pivoter l'écran peut interrompre votre tâche Thread ou Async du réseau en cours d'exécution, qui sera détruite avec son activité parent. Pour les threads démarrés via l'action de l'utilisateur, l'opération sera effectivement annulée. PourLes threads lancés dans les gestionnaires de cycle de vie de l'activité, tels que onCreate ou onStart, seront recréés et réexécutés lorsque l'activité est recréée, ce qui risque d'exécuter plusieurs fois la même opération de réseau. Cela peut entraîner des transferts de données en double et une durée de vie de la batterie plus courte. Une meilleure approche consiste à utiliser les classes ViewModel et LiveData fournies dans le cadre des composants d'architecture Android. Tous les modèles de vues associés à une activité ou à un fragment sont conçus spécifiquement pour persister dans les modifications de configuration, fournissant ainsi une mise en cache des données stockées. Les données d'un modèle de vue sont généralement renvoyées sous forme de données en direct. Live Data est une classe sensible au cycle de vie utilisée pour stocker et fournir des mises à jour observables pour les données d'application. La conscience du cycle de vie signifie que Live Data envoie uniquement les mises à jour aux observateurs dans les composants d'application qui sont dans un état de cycle de vie actif. Pour utiliser View Models et Live Data, vous devez d’abord ajouter des composants d’architecture Android au fichier Gradle Build de votre module d’application:

 

  1. dependencies {
  2. [... Existing dependencies nodes ...]
  3. implementation "android.arch.lifecycle:extensions:1.1.1" }

 Le Listing 7-2 montre une implémentation simple de View Model qui tire parti de la norme

 Classe MutableLiveData. Il utilise une tâche asynchrone pour télécharger et analyser une ressource Internet en arrière-plan et renvoie le résultat sous forme de données en direct représentant une liste de chaînes.

LISTING 7-2: Utilisation d'un modèle de vue pour le téléchargement sur un thread d'arrière-plan à l'aide d'une tâche asynchrone

 

  1. public class MyViewModel extends AndroidViewModel {
  2. private static final String TAG = "MyViewModel";
  3. private final MutableLiveData<List<String>> data;
  4. public MyViewModel(Application application) {
  5. super(application);
  6. }
  7. public LiveData<List<String>> getData() {
  8. if (data == null)
  9. data = new MutableLiveData<List<String>>();
  10. loadData();
  11. }
  12. return data;
  13. }
  14. private void loadData() {
  15. new AsyncTask<Void, Void, List<String>>() {
  16. @Override
  17. protected List<String> doInBackground(Void... voids) {
  18. ArrayList<String> result = new ArrayList<>(0);
  19. String myFeed = getApplication().getString(R.string.my_feed);
  20. try {
  21. URL url = new URL(myFeed);
  22. // Create a new HTTP URL connection
  23. URLConnection connection = url.openConnection();
  24. HttpURLConnection httpConnection = (HttpURLConnection) connection;
  25. int responseCode = httpConnection.getResponseCode();
  26. if (responseCode == HttpURLConnection.HTTP_OK) {
  27. InputStream in = httpConnection.getInputStream();
  28. // Process the input stream to generate our result list
  29. result = processStream(in);
  30. }
  31. httpConnection.disconnect();
  32. } catch (MalformedURLException e) {
  33. Log.e( TAG, "Malformed URL Exception.", e);
  34. } catch (IOException e) {
  35. Log.e( TAG, "IO Exception.", e);
  36. }
  37. return result;
  38. }
  39. @Override
  40. protected void onPostExecute(List<String> data) {
  41. // Update the Live Data data value.
  42. data.setValue(data);
  43. }
  44. }.execute();
  45. }
  46. }

Pour utiliser un modèle de vue dans votre application, vous devez d’abord créer une nouvelle instance (ou renvoyer l’instance existante) de votre modèle de vue dans l’activité ou le fragment qui observera les données en direct. Utilisez la méthode statique de la classe ViewModelProviders - en transmettant le composant d’application actuel - pour extraire les modèles de vue disponibles et utilisez la méthode get pour spécifier le modèle de vue que vous souhaitez utiliser:

  1. MyViewModel myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);

 Une fois que vous avez une référence à votre modèle de vue, vous devez ajouter un observateur afin de recevoir le message.Live Data qu'il contient. Appelez getData sur le modèle de vue, puis utilisez la méthode observe pour ajouter une implémentation Observer dont le gestionnaire onChanged sera déclenché à chaque modification des données sous-jacentes:

 

  1. myViewModel.getData().observe(this, new Observer<List<String>>() {
  2. @Override
  3. public void onChanged(@Nullable List<String> data) {
  4. // TODO When new View Model data is received, update the UI.
  5. }
  6. }) ;

Le processus complet d'obtention d'un modèle de vue pour votre activité, de demande de données en direct et d'observation de modifications est présenté dans le Listing 7-3. 

LISTING 7-3: Utilisation de Live Data et d'un modèle de vue d'une activité

 

  1. @Override
  2. protected void onCreate(Bundle savedInstanceState) {
  3. super.onCreate(savedInstanceState);
  4. setContentView(R.layout.activity_main);
  5. // Obtain (or create) an instance of the View Model
  6. MyViewModel myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
  7. // Get the current data and observe it for changes.
  8. myViewModel.getData().observe(this, new Observer<List<String>>() {
  9. @Override
  10. public void onChanged(@Nullable List<String> data) {
  11. // Update your UI with the loaded data.
  12. // Returns cached data automatically after a configuration change,
  13. // and will be fired again if underlying Live Data object is modified.
  14. }
  15. });
  16. }

Parce que votre cycle de vie View Model est basé sur votre application (et non sur l’activité ou le fragment parent), la fonction de chargement de Live Data de View Model ne sera pas interrompue par un changement de configuration de périphérique. De même, vos résultats sont implicitement mis en cache lors des modifications de la configuration du périphérique. Après une rotation, quand observe est appelé dans les données du modèle de vue, il renvoie immédiatement le dernier jeu de résultats via le gestionnaire onChanged - sans que la méthode loadData de View Model soit appelée. Cela permet d'économiser beaucoup de temps et d'énergie sur la batterie en éliminant les téléchargements dupliqués sur le réseau et le traitement associé. Au chapitre 11, vous découvrirez des API plus puissantes pour la planification des opérations réseau en arrière-plan, qui prennent en compte le minutage et l'état des périphériques afin d'améliorer l'efficacité de vos transferts réseau.