Vous êtes sur la page 1sur 82

Développement Mobile

- Natif avec Android


- Cross Platform : Flutter

Mohamed Youssfi
Laboratoire Signaux Systèmes Distribués et Intelligence Artificielle (SSDIA)
ENSET, Université Hassan II Casablanca, Maroc
Email : med@youssfi.net
Supports de cours : http://fr.slideshare.net/mohamedyoussfi9
Chaîne vidéo : http://youtube.com/mohamedYoussfi
Recherche : http://www.researchgate.net/profile/Youssfi_Mohamed/publications
Développement Mobile

• Deux manières pour développer des applications mobiles : Java, Kotlin


Android SDK
ObjectiveC, Swift
IOS SDK
C#
Win Phone SKD
• Développement mobile natif : Android Studio XCode Visual Studio

• Android : Java (Kotlin), Android SDK, Android Studio, Google Play


• IOS : Objective C (Swift), IOS SDK, XCode, Apple App Store
• Windows Phone : C#, Windows Phone SDK, Visual Studio,
Microsoft Masketplace
• Développement mobile Cross Platform :
• Hybride :
• HTML, CSS, Java Script pour la partie IHM
• Apache CORDOVA pour la partie native
• Plateformes : Adobe PhoneGap, IBM MobileFirst, IONIC,
• Native Cross Platform :
• React Native : Java Script avec le Framework ReactJS
• Xamarin : C# avec le Framework .Net
HTML, CSS, Java Script, CORDOVA
• Flutter : Dart, Flutter Framework
Développement Mobile Cross Platform
Hybrid Approach : IONIC, PhoneGap, Mobile First Flutter Approach

Flutter Widgets
Web View Cupertino
Material Design
HTML Native
CSS ARM
Java Binary
Script Code
Platform
Channels

• Hybrid Approach (IONIC):


• Utilise le moteur de rendu HTML, CSS du Web View pour la logique présentation
Native Cross Plaform Approach : React Native, Xamarin
• Utilise du Java Script pour exécuter les traitements
• Pour accéder aux fonctionnalités natives de l’appareil mobile, il utilise un Bridge (Plugings
CORDOVA)

Transform Bridge: OEM Widgets


• React Native :
(Capertini, Materal • Utilise ses proposes Composants pour la logique présentation, qui seront mappé en
ed Native
Design) composant OEM Natif de l’appareil Mobile
Code SDK
Librairies • Utilise Java Script pour les traitements avec React JS Comme Framework
(Non • Utilise un Bridge Java Script pour accéder aux fonctionnalités Natives
Ou
Reactive) • Flutter :
• Utilise ses propres composants natifs pour la logique présentation. Flutter utilise son propore
Java
Java Script moteur de rendu SKIA pour dessiner les éléments de l’interface.
Script Bridge • Utilise Native ARM Binary Code pour la logique applicative
(Reactive) (Reactive) • Utilise un Channel pour la transmission de message aux fonctionnalités natives
Développement Natif ANDROID
Java
• Android est un OS mobile Open Source pour smartphone, PDA, MP3 et tablette. Android SDK
Android Studio

• Conçu initialement par Android Inc , il a été racheté par Google en 2005.
• Android est conçue pour des appareils mobiles au sens large.
• Il ouvre d’autres possibilités d’utilisation pour les Smartphones, tablettes,...
• La plate-forme Android est composée de différentes couches :
• Un noyau Linux
• Des bibliothèques graphiques, multimédia
• Une machine virtuelle JAVA adaptée: Dalvik Virtual Machine
• Le Framework Android pour la gestion de fenêtres ,de téléphonie ,de gestion de
contenu et des fonctionnalités natives du dispositif mobile
• Des applications dont un navigateur web ,une gestion de contacts, une
calendrier,..
Java
Android SDK
Android Studio

Architecture de ANDROID

• Linux kernel
• Libraires
• Android Runtime
• Core Librairies
• JVM (Dalvik)
• Application Framework
• Application Widgets
Java
Android SDK
Android Studio

Composants d’une Application ANDROID


User
• Activités (Activity) :

• Composant Principal d’une app Android.

• Contrôleur de l’App qui affiche des vues (Layouts) contenant des données
provenant des modèles.
Activities (Model, Controller, View)
• Réagit aux événements des interactions utilisateurs sur les vues.
Broadcast Contents
• Services : Services
Receivers Providers
• Traitements de fond associé à une application Mobile Android Applications
• Récepteurs de diffusion (Broadcast Receivers) :
Android Framework Container
• Gèrent la communication entre le système d’exploitation Android et les JVM (Dalvik)
applications.
Native Librairies
• La communications entres les composants des applications Android se fait
par envoie de message via des « Intent » OS : LINUX

• Fournisseurs de contenu (Contents providers) :


Smatphone Device

• Permettre l’accès aux données : Contacts, Agenda, Photos, etc…


Java
Android SDK
Android Studio

Structure d’une activité


Etendre la classe Activity ou ses sous classes comme CompactActivity et redéfinir les méthodes associées au cycle de vie d’une activité Android

import android.app.Activity; @Override


import android.os.Bundle; protected void onPause() {
import android.support.annotation.Nullable; super.onPause();
}
public class MyActivity extends Activity { @Override
protected void onStop() {
@Override
super.onStop();
protected void onCreate(@Nullable Bundle savedInstanceState) {
}
super.onCreate(savedInstanceState);
@Override
} protected void onDestroy() {
@Override super.onDestroy();
protected void onStart() { }
super.onStart(); @Override
} protected void onSaveInstanceState(Bundle
@Override outState) {
protected void onResume() { super.onSaveInstanceState(outState);
super.onResume(); }
}
}
Java
Android SDK
Android Studio

Cycle de vie d’une Activity


• Lorsque l’activité est lancée, le système Android appelle les méthodes onCreate,
onStart et onResume.

• Lorsque l’activité s’arrête, le système Android appelle les méthodes onPause, onStop
et onDestroy.

• Lorsque l’activité n’est plus au premier plan, mais qu’elle est tout de même affichée,
onPause est appelée. Lorsque l’activité retourne au premier plan, onResume est
appelée.

• Lorsque l’activité n’est plus affichée, onPause et onStop sont appelées. Lorsque
l’activité est de nouveau affichée, onRestart, onStart et onResume sont appelées.

• Lorsque le système Android décide de tuer votre application, il appelle la méthode


onSaveInstanceState qui vous permet de sauvegarder l’état de votre activité. Cet état
sera passé en paramètre à la méthode onCreate, afin que vous puissiez restaurer l’état
de l’activité.

• Le système Android s’occupe lui-même de sauvegarder et restaurer l’état des vues des
layouts, à condition que ces vues aient chacune un ID unique dans le layout.

• Le changement de configuration comme le changement d’orientation de l’écran


provoque un redémarrage de l’activité, vous devez donc sauvegarder et restaurer
l’état dans ce cas.
Java
Android SDK
Android Studio

Outils de développement Android

• Installer Le Kit de développement Java (Version 8):

• https://www.oracle.com/technetwork/java/javase/downloa
ds/jdk8-downloads-2133151.html

• Installer le SDK Android et IDE Android Studio :

• https://developer.android.com/studio#downloads

• Une fois Android Studio installé et démarré,

• Si Android SDK n’est pas installé, il vous demandera de


procéder à son installation.
Java
Android SDK
Android Studio

SDK Manager

• Une fois que vous lancez Android


Studio et que Android SDK est
bien installé, il est important de
savoir les versions des API SDK
Android installées.

• Vous pouvez le faire via l’outil


SDK Manager accessible par le
menu Outils>Sdk Manager.

• Dans notre cas ici, nous pouvons


constater que les API version 26
et 27 sont installées.
Java
Android SDK
Android Studio

Android Virtual Devise


• Pour tester vos applications
Android, vous aurez besoin d’un
Emulateur Android.
• Les Gestion des émulateurs
Android sont accessibles par le
menu Tools>AVD Manager.
• Avec le bouton Create Virtual
device, vous pouvez ajouter
différences versions d’émulateurs
virtuel.
• Le démarrage d’un émulateur
consomme beaucoup de
ressources. Il est donc important
pour vous d’avoir le réflex de le
démarrer au moment opportun et
de ne pas l’arrêter à chaque fois.
• Si l’émulateurs
Java
Android SDK
Android Studio

Premier Projet Android


• File > New Project

• Spécifier le nom du projet et un nom de


domaine de votre choix

• Next

• Spécifier les information concernant le


type d’appareil cible

• Next

• Choisir le modèle d’application à


générer. Dans notre cas, on va choisir
Empty Activity pour ne pas générer un
projet vide.

• Next

• Spécifier le nom de l’activité principale


de démarrage de votre application.

• Finish
Java
Android SDK
Android Studio

Structure d’un projet Android Studio

• Un projet Android Studio est un projet Java basé sur Gradle.

• Gradle est un outil qui permet l’automatisation des opérations de


construction d’une application Java tout comme Maven (Compiler les
sources, Lancer les tests unitaires, générer l’APK finale de l’application
andoid, exécuter l’application dans l’émulateur, etc…).

• Un projet Gradle contient un fichier build.gradle dans lequel, on déclare :

• Les dépendances du projets (Les librairies à utiliser). Vous pouvez


constater par exemple qu’il fait appel à JUINIT pour les tests unitaires.

• Les versions des API Android SDK à utiliser ou moment de compilation


et de génération des builds

• Etc..

• Pour le moment vous n’aurez pas besoin de modifier ce fichier.


Java
Android SDK
Android Studio

Structure d’un projet Android Studio


• Les éléments les plus important de votre projet sont :

• Dossier Java :

• MainActivity.java : L’activité principale

• ExampleUnitTest.java : Un simple exemple de Test Unitaire basé sur Junit

• ExampleInstrumentedTest : Un exemple de test unitaire faisant appel à AndroidJUnit

• Dossier res (Resources):

• dossier layout : contient les vues de l’application au format xml :

• activity_main.xml : La vue principale qui sera affichée par MainActivity

• Dossier values : contient des fichiers xml qui contiennent des ressources affichées par
l’application

• strings.xml : contient les valeurs des chaines de caractères affichées par les vues

• colors.xml : pour déclarer des couleurs

• styles.xml : pour déclarer des styles pour le thème de l’application

• Dossier drawable contient des ressources images de l’application.


Java
Android SDK
Android Studio

AndroidManifest.xml
• Premier Fichier lu par Android Framework au démarrage de l’appli
• On y déclare entre autres :
• Activité de démarrage de l’application, Activités, Services, etc
• Autorisations attribuées à l’application (Internet,, Géolocalisation, etc…)

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.youssfi.myfirstmobileapp">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Java
Android SDK
Android Studio

Classe de ressources R.Java

• Pour manipuler facilement dans le code java


des activité les différentes ressources déclarées
dans l’application, un projet Android utilise
une classe très importante en lecture seule
package net.youssfi.myfirstmobileapp;

R.java public final class R {


public static final class id {
public static final int ALT=0x7f070000;
• Cette classe statique déclare des constantes public static final int CTRL=0x7f070001;
dont les valeurs représentent des identifiants ...
}
des ressources. Le contenu de cette classe est
public static final class layout {
défini automatiquement par Android Studio. public static final int activity_main=0x7f09001b;

• Vous comprendrez l’utilité de cette classe dans ...

les sections suivantes. }

...

}
Java
Android SDK
Android Studio
Android MainAvtivity View
MainActivity.java et activity_main.xml
Lire
package net.youssfi.myfirstmobileapp; Manifest.xml
Instancier
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; onCreate
Load Bundle
public class MainActivity extends AppCompatActivity { Activity Stat
loadView
@Override activity_main.xml
protected void onCreate(Bundle savedInstanceState) {
onStart
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
onResume
}
}

<?xml version="1.0" encoding="utf-8"?>


<android.support.constraint.ConstraintLayout Hello World
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">

<TextView android:text="Hello World!« />


</android.support.constraint.ConstraintLayout>
Java
Android SDK
Android Studio

activity_main.xml

Hello World
Java
Android SDK
Android Studio

Exécution de l’application sur un émulateur

Hello World

• En exécutant l’application, vous faites appel à Graddle pour recompiler et construire l’application.

• Cette opération nécessite de sélectionner l’instance de l’émulateur à utiliser pour installer


l’application.

• Sélectionner l’instance de l’émulateur ayant été déjà démarrée ou démarre une nouvelle instance
Java
Android SDK
Android Studio

Générer l’application APK

• Les applications que vous installez dans un appareil Android sont


des fichiers au format APK (Android Package Kit).
• C’est un fichier au format Zip qui contient les éléments de
l’application android:
• AndroidManifest.xml
• Byte code des classes Java au format DEX optimisé pour la
JVM de Dalvik. Ces fichiers sont obtenus en transformant le
byte code des classes (.class) au format DEX en utilisant un
outil DX.
• Ressources : XML, Images, audio, vidéos
• Eventuelles Librairies additionnelle (.jar)
• Pour générer le fichier APK signé:
• Menu Build > Generate Signed APK
Java
Android SDK
Android Studio

Générer l’application APK

• Pour générer le fichier APK signé:

• Menu Build > Generate Signed APK


Java
Android SDK
Android Studio

Ressources String.xml

• Les chaines constantes de l'application sont


situées dans res/values/strings.xml.
• L'externalisation des chaines permettra de
réaliser l'internationalisation de l'application.
• Voici un exemple:

<resources>
<string name="app_name">MyFirstMobileApp</string>
<string name="label_message">Hello Word</string>
</resources>
Java
Android SDK
Android Studio

Ressources

• Les ressources sont utilisées de la manière suivante:


• R.type_ressource.nom_ressource
• qui est de type int.
• Il s'agit en fait de l'identifiant de la ressource.
• On peut alors utiliser cet identifiant ou récupérer l'instance de
la ressource en utilisant la classe Resources:
• Resources res= getResources();
• String s=res.getString(R.string.label_message);

<resources>
<string name="app_name">MyFirstMobileApp</string>
<string name="label_message">Hello Word</string>
</resources>
Java
Android SDK
Android Studio

Ressources

Une méthode spécifique pour les objets graphiques


permet de les récupérer à partir de leur id, ce qui
permet d'agir sur ces instances même si elles ont été
créées via leur définition XML:
Java
Android SDK
Android Studio

Ressources

• Le système de ressources permet de gérer très MyProject/


res/
facilement l'internationalisation d'une application. values/
strings.xml
• Il suffit de créer des répertoires values-XX où XX est values-es/
le code de la langue que l'on souhaite implanter. strings.xml
values-fr/
• On place alors dans ce sous répertoire le fichier xml strings.xml

strings.xml contenant les chaines traduites associées


aux même clefs que dans values/strings.xml.
• On obtient par exemple pour les langues es et fr
l'arborescence:
Java
Android SDK
Android Studio

Ressources de type Array

• Plusieurs fichies xml peuvent être placés dans res/values. MyProject/


res/
• Cela permet de définit des chaines, des couleurs, des values/
strings.xml
tableaux.
values-es/
• L'assistant de création permet de créer de nouveaux strings.xml
values-fr/
fichiers de ressources contenant des valeurs simples, strings.xml
comme par exemple un tableau de chaines:

<?xml version="1.0" encoding="utf-8"?>


<resources>
<string-array name="test">
<item>it1</item>
<item>it2</item>
</string-array>
</resources>
Java
Android SDK
Android Studio

Autres ressources

• D'autres ressources sont spécifiables dans res: MyProject/


res/
• layout : pour les Vues XML layout
• Menus : pour les déclarer les menus values
drawable
• drawable (R.drawable) : pour les images dimen/
• des dimensions (R.dimen )
• des couleurs (R.color)
Première Application Android

L’objectif étant de créer une simple application mobile Android qui permet de :

• Saisir un nombre représentant un montant en Euro dans un composant de


type « EditText »

• Convertir le montant saisi en DH en le multipliant par le taux de change

• Afficher le résultat dans un champ de type TextView.

• Ajouter l’historiques des conversions dans un ListView


Première Application Android
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <TextView
<LinearLayout android:id="@+id/textViewResult"
xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools" android:text="0"
android:layout_width="match_parent" android:layout_margin="10dp"
android:layout_height="match_parent" android:background="@drawable/text_view_style"
android:orientation="vertical" android:padding="10dp"
android:padding="10dp" android:textAlignment="center"
android:layout_margin="10dp" android:textSize="22dp"
tools:context=".MainActivity"> android:textColor="@color/colorPrimary"
/>
<ListView
<EditText android:id="@+id/listViewResults"
android:id="@+id/editTextAmount" android:layout_width="match_parent"
android:layout_width="match_parent" android:layout_height="match_parent"
android:layout_height="wrap_content" android:layout_margin="10dp"
android:background="@drawable/edit_text_style" />
android:inputType="number"
android:layout_margin="10dp" </LinearLayout>
android:padding="10dp"
/>
<Button
android:id="@+id/btnCompute"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/colorPrimary"
android:textColor="@color/white"
android:text="Compute"
android:layout_margin="10dp"
/>
Ressources
<resources> styles.xml
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

<resources> values.xml
<string name="app_name">First App</string>
<string name="hw">Hello BDCC</string>
</resources>

<?xml version="1.0" encoding="utf-8"?> colors.xml


<resources>
<color name="colorPrimary">#FF5722</color>
<color name="colorPrimaryDark">#FFC107</color>
<color name="colorAccent">#03DAC5</color>
<color name="white">#FFFFFF</color>
</resources>
Ressources

<?xml version="1.0" encoding="utf-8"?> Edit_text_style


<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="@color/colorPrimary"></stroke>
<size android:height="40dp"></size>
</shape>
</item>
<?xml version="1.0" encoding="utf-8"?> Text_view_style.xml
</selector>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="rectangle">
<stroke android:width="1dp" android:color="@color/colorPrimaryDark"></stroke>
<size android:height="40dp"></size>
</shape>
</item>
</selector>
Ressources
package net.youssfi.tp_and; ActivityMain.java
import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;

import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Code à ajouter
}
}
Ressources

@Override ActivityMain.java
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Code à ajouter
EditText editTextAmount=findViewById(R.id.editTextAmount);
Button btnCompute=findViewById(R.id.btnCompute);
TextView textViewResult=findViewById(R.id.textViewResult);
ListView listViewResult=findViewById(R.id.listViewResults);
List<String> data=new ArrayList<>();
ArrayAdapter<String> stringArrayAdapter=new
ArrayAdapter<>(this,android.R.layout.simple_list_item_1,data);
listViewResult.setAdapter(stringArrayAdapter);
btnCompute.setOnClickListener((view)->{
double amount=Double.parseDouble(editTextAmount.getText().toString());
double result=amount*11;
textViewResult.setText(String.valueOf(result));
data.add(amount+"=>"+result);
stringArrayAdapter.notifyDataSetChanged();
editTextAmount.setText("");
});
}
Application 2

• L’objectif étant de créer un simple jeu en plusieurs


langues (Français, Anglais, Arabe) qui permet de :

• Générer un nombre secrêt aléatoire entre 1 et 100.

• L’utilisateur devrait deviner le nombre secret en


plusieurs tentatives.

• Pour chaque tentative le jeu répond par l’une des


indications suivantes:

• Votre nombre est plus petit

• Votre nombre est plus grand

• BRAVO

• Le numéro de la tentative est affiché et aussi


indiqué par une Progess Bar.

• Pour chaque partie gagnée le score s’incrémente


de 5 points.

• L’historiques des essais est affiché dans ListView.


Application 2 : activity_main.xml
<Button
<?xml version="1.0" encoding="utf-8"?> android:id="@+id/buttonOK"
android:layout_width="101dp"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_alignParentEnd="true"
xmlns:tools="http://schemas.android.com/tools" android:layout_below="@+id/textView"
android:text="OK" />
android:layout_width="match_parent"
android:layout_height="match_parent" <ProgressBar
android:padding="@dimen/default_padding" android:id="@+id/progressBarScore"
style="?android:attr/progressBarStyleHorizontal"
tools:context=".MainActivity">
android:layout_width="527dp"
android:layout_height="wrap_content"
<TextView android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:id="@+id/textView"
android:layout_below="@+id/buttonOK"
android:layout_width="172dp" android:layout_marginEnd="55dp"
android:layout_height="wrap_content" android:layout_marginTop="98dp"
android:max="10"
android:layout_alignParentStart="true"
android:progress="5" />
android:layout_alignParentTop="true"
android:text="@string/text_devinez" <TextView
android:id="@+id/textViewIndication"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
android:layout_width="374dp"
android:layout_height="wrap_content"
<EditText android:layout_alignParentStart="true"
android:id="@+id/editTextNumber" android:layout_below="@+id/progressBarScore"
android:text="..."
android:layout_width="234dp"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:layout_height="wrap_content" android:textColor="@color/colorAccent" />
android:layout_alignParentStart="true"
<ListView
android:layout_below="@+id/textView"
android:ems="10"
android:inputType="number" />
Application 2 : activity_main.xml
android:id="@+id/lisViewHisto" <TextView
android:id="@+id/textView4"
android:layout_below="@+id/textViewIndication"
android:layout_width="110dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="349dp"
android:layout_alignTop="@+id/textView"
android:layout_alignParentBottom="true" android:layout_marginEnd="-87dp"
android:layout_alignParentStart="true" /> android:layout_toStartOf="@+id/buttonOK"
android:text="@string/str_score"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
<TextView
android:id="@+id/textViewScore"
<TextView
android:layout_width="52dp"
android:id="@+id/textViewScoreCumul"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:layout_alignBottom="@+id/progressBarScore" android:layout_height="wrap_content"

android:layout_alignParentEnd="true" android:layout_alignParentEnd="true"
android:layout_alignTop="@+id/textView"
android:text="0"
android:layout_marginEnd="0dp"
android:textAlignment="viewEnd"
android:text="0"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" android:textColor="@color/colorAccent" />
android:textColor="?attr/colorAccent"
android:textStyle="bold" /> </RelativeLayout>
Application 2 : ActivityMain.java
package net.youssfi.jeuandroidapp;
import android.content.DialogInterface;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle; import android.util.Log;
import android.widget.*; import java.util.ArrayList;
import java.util.List;

public class MainActivity extends AppCompatActivity {


private Button buttonOK; private EditText editTextNumber;
private ListView listViewHisto; private TextView textViewIndication;
private ProgressBar progressBarScore; private TextView textViewScore;
private TextView textViewScoreCumul; private int secret;
private int nombreEssais=1; private int nombreMaxEssais=6;
private List<String> historique=new ArrayList<>(); private ArrayAdapter<String> adapter;
private int scoreCumule;
Application 2 : ActivityMain.java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextNumber=findViewById(R.id.editTextNumber);
listViewHisto=findViewById(R.id.lisViewHisto);
textViewIndication=findViewById(R.id.textViewIndication);
textViewScore=findViewById(R.id.textViewScore);
progressBarScore=findViewById(R.id.progressBarScore);
buttonOK=findViewById(R.id.buttonOK);
textViewScoreCumul=findViewById(R.id.textViewScoreCumul);
adapter=new ArrayAdapter(this,android.R.layout.simple_list_item_1,historique);
listViewHisto.setAdapter(adapter);
initialisation();
Application 2 : ActivityMain.java
buttonOK.setOnClickListener((evt)->{
String str=editTextNumber.getText().toString();
int number=0;
try{
number=Integer.parseInt(str);
}catch (NumberFormatException ex){
ex.printStackTrace();
return;
}
historique.add(nombreEssais+" =>:"+number);
adapter.notifyDataSetChanged();
Log.i("MyInfos",getString(R.string.essai_numero)+
String.valueOf(nombreEssais)+"=>"+String.valueOf(number));

textViewScore.setText(String.valueOf(nombreEssais));
progressBarScore.setProgress(nombreEssais);
Application 2 : ActivityMain.java
if(number>secret){
textViewIndication.setText(getString(R.string.nombre_plus_grand));
}
else if(number<secret){
textViewIndication.setText(getString(R.string.nombre_plus_petit));
}
else{
textViewIndication.setText(R.string.bravo);
scoreCumule+=5; retry();
}
editTextNumber.setText("");
if((number!=secret)&&(nombreEssais>nombreMaxEssais)){
retry();
}
++nombreEssais;
} );
}
Application 2 : ActivityMain.java
private void retry(){
AlertDialog alertDialog=new AlertDialog.Builder(this).create();
alertDialog.setTitle(getString(R.string.str_nouvel_essai));
alertDialog.setButton(AlertDialog.BUTTON_POSITIVE, "OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
initialisation();
}
});
alertDialog.setButton(AlertDialog.BUTTON_NEGATIVE, "Finish", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
finish();
}
});
alertDialog.show();
}
Application 2 : ActivityMain.java

private void initialisation() {


this.nombreEssais=1;
this.secret=1+((int)(Math.random()*100));
this.editTextNumber.requestFocus();
this.progressBarScore.setProgress(nombreEssais);
this.textViewIndication.setText("");
this.editTextNumber.setText("");
this.textViewScore.setText(String.valueOf(nombreEssais));
textViewScoreCumul.setText(String.valueOf(scoreCumule));
historique.clear();
adapter.notifyDataSetChanged();
}

}
Application 2 : strings.xml
<resources>
<string name="app_name">Random Game</string>
<string name="text_devinez">Guess</string>
<string name="nombre_plus_grand">Number is greater</string>
<string name="nombre_plus_petit">Number is smaller</string>
<string name="bravo">Congratulation!</string> <?xml version="1.0" encoding="utf-8"?>
<string name="str_score">Score:</string> <resources>
<string name="essai_numero">Round number:</string> <string name="app_name">Jeu Hazard</string>
<string name="str_nouvel_essai">New Round?</string> <string name="text_devinez">Devinez</string>
</resources> <string name="nombre_plus_grand">Nombre plus grand</string>
<string name="nombre_plus_petit">Nombre plus petit</string>
<string name="bravo">Bravo!</string>
<string name="str_score">Score:</string>
<string name="essai_numero">Essai Numéro:</string>
<string name="str_nouvel_essai">Nouvel essai?</string>
</resources>
Application 2 : AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.youssfi.jeuandroidapp">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
Application 3 : Météo

• Créer une application mobile Android qui


permet de :
• Saisir une ville Backend
• Afficher les prévisions météo de cette HTTP
API REST
ville en faisant appel à l’API REST exposé JSON
Openweather.org
par openweather.org. On affichera pour
chaque prévision :
• Date et heure
• Température maximale
• Température minimale
• Pression atmosphérique
• Humidité
https://samples.openweathermap.org/data/2.5/forecast?q=mohammedia,DE&appid=b6907d289e10d714a6e88b30761fae22

Openweather.org
Application 3 : Météo

build.gradle
dependencies {

implementation
'com.android.volley:volley:1.1.0'
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-
layout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation
'com.android.support.test:runner:1.0.2'
androidTestImplementation
'com.android.support.test.espresso:espresso-core:3.0.2'
}
Application 3 : AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.youssfi.httpandroidapp">
<uses-permission android:name="android.permission.INTERNET" />

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Application 3 : app_shape.xml et input_shape.xml
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<stroke android:width="2dp" android:color="@color/colorPrimary" ></stroke>
<solid android:color="@color/colorAccent"></solid>
</shape>

<?xml version="1.0" encoding="utf-8"?>


<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke android:width="2dp" android:color="@color/colorAccent" ></stroke>
</shape>
Application 3 : activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity" android:padding="10dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/textView2"
android:layout_width="73dp"
android:layout_height="wrap_content"
android:text="Ville :"
android:textAppearance="@style/TextAppearance.AppCompat.Large"
android:layout_margin="5dp"/>/>
</LinearLayout>
Application 3 : activity_main.xml <EditText
android:id="@+id/editTextVille"
android:layout_width="250dp"
android:layout_height="wrap_content"
android:layout_margin="5dp"
android:background="@drawable/input_shape"
android:ems="10"
android:inputType="textPersonName"
android:padding="5dp" />
<ImageButton
android:id="@+id/buttonOK"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
app:srcCompat="@android:drawable/ic_media_play"
android:background="@drawable/app_shapes"
android:layout_margin="5dp"/>/>
</LinearLayout>
<ListView
android:id="@+id/listViewMeteo"
style="@android:style/Widget.Material.ListView"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
Application 3 : list_item_layout.xml
Application 3 : list_item_layout.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout
<LinearLayout android:layout_width="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
xmlns:tools="http://schemas.android.com/tools"
android:padding="10dp">
android:layout_width="match_parent"
android:layout_height="wrap_content"> <TextView
<ImageView android:id="@+id/textViewDate"
android:id="@+id/imageView" android:layout_width="match_parent"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="textStart"
android:layout_gravity="center_vertical"
android:textAppearance="@style/TextAppearance.App
tools:srcCompat="@tools:sample/avatars" />
Compat.Medium"
android:textStyle="bold" />
Application 3 : list_item_layout.xml
<LinearLayout
<TextView

android:layout_width="match_parent" android:id="@+id/textViewTempMin"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:orientation="horizontal"> android:layout_height="wrap_content"
<TextView
android:layout_weight="1"
android:id="@+id/textView"
android:textAlignment="textStart"
android:layout_width="93dp"
android:textAppearance="@style/TextAppearanc
android:layout_height="wrap_content"
android:text="Min:"
e.AppCompat.Medium" />

android:textAlignment="textStart" </LinearLayout>
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
/>
Application 3 : list_item_layout.xml
<TextView
<LinearLayout
android:id="@+id/textViewTempMAX"
android:layout_width="match_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:layout_weight="1"
<TextView
android:textAlignment="textStart"
android:id="@+id/textView4"
android:textAppearance="@style/TextAppearance
android:layout_width="93dp"
.AppCompat.Medium" />
android:layout_height="match_parent"
</LinearLayout>
android:text="MAX:"
android:textAlignment="textStart"
android:textAppearance="@style/TextAppearance.AppCompat.
Medium" />
Application 3 : list_item_layout.xml
<LinearLayout <TextView

android:layout_width="match_parent" android:id="@+id/textViewPression"
android:layout_width="166dp"
android:layout_height="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
android:textAlignment="textStart"
<TextView
android:textAppearance="@style/TextAppearance.AppCo
android:id="@+id/textView6" mpat.Medium" />
android:layout_width="93dp" </LinearLayout>
android:layout_height="wrap_content"
android:text="Pression:"
android:textAlignment="textStart"
android:textAppearance="@style/TextAppearance.AppCompa
t.Medium" />
<TextView
Application 3 : list_item_layout.xml android:id="@+id/textViewHumidite"
android:layout_width="match_parent"
<LinearLayout
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:textAlignment="textStart"
android:layout_height="wrap_content"
android:textAppearance="@style/TextAppearance.AppCo
android:orientation="horizontal">
mpat.Medium" />
<TextView
</LinearLayout>
android:id="@+id/textView9"
</LinearLayout>
android:layout_width="93dp"
</LinearLayout>
android:layout_height="wrap_content"
android:text="Humidité:"
android:textAlignment="textStart"
android:textAppearance="@style/TextAppearance.AppC
ompat.Medium" />
MainActivity.java
package net.youssfi.httpandroidapp;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ListView;
import com.android.volley.Request;
import com.android.volley.RequestQueue;
import com.android.volley.Response;
import com.android.volley.VolleyError;
import com.android.volley.toolbox.StringRequest;
import com.android.volley.toolbox.Volley;
import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONObject;
import java.text.SimpleDateFormat; import java.util.ArrayList;
import java.util.Date;
import java.util.List;
MainActivity.java
public class MainActivity extends AppCompatActivity {
private EditText editTextVille; private ListView listViewMeteo;
//private List<String> data=new ArrayList<>();
List<MeteoItem> data=new ArrayList<>();
//private ArrayAdapter<String> model;
private MeteoListModel model; private ImageButton buttonOK;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editTextVille=findViewById(R.id.editTextVille);
listViewMeteo=findViewById(R.id.listViewMeteo);
buttonOK=findViewById(R.id.buttonOK);
model=new MeteoListModel(getApplicationContext(),R.layout.list_item_layout,data);
listViewMeteo.setAdapter(model);
//model=new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,data);
MainActivity.java
buttonOK.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Log.i("MyLog","......");
data.clear(); model.notifyDataSetChanged();
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
String ville=editTextVille.getText().toString();
Log.i("MyLog",ville);
String url
="https://samples.openweathermap.org/data/2.5/forecast?q="+ville+"&appid=a457
8e39643716894ec78b28a71c7110";
StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
new Response.Listener<String>() {
MainActivity.java
@Override
public void onResponse(String response) {
try {
Log.i("MyLog","----------------------------");
Log.i("MyLog",response);
List<MeteoItem> meteoItems=new ArrayList<>();
JSONObject jsonObject=new JSONObject(response);
JSONArray jsonArray=jsonObject.getJSONArray("list");
for (int i=0;i<jsonArray.length();i++){
MeteoItem meteoItem=new MeteoItem();
JSONObject d=jsonArray.getJSONObject(i);
Date date=new Date(d.getLong("dt")*1000);
SimpleDateFormat sdf = new SimpleDateFormat("dd-MMM-yyyy'T'HH:mm");
String dateString = sdf.format(date);
JSONObject main=d.getJSONObject("main");
JSONArray weather=d.getJSONArray("weather");
int tempMin=(int)(main.getDouble("temp_min")-273.15);
int tempMax=(int)(main.getDouble("temp_max")-273.15);
MainActivity.java
int pression=main.getInt("pressure");
int humidity=main.getInt("humidity");
//data.add(String.format(dateString+"\n"+"Min=%d °c, Max=%d °C",tempMin,tempMax));
meteoItem.tempMax=tempMax; meteoItem.tempMin=tempMin;
meteoItem.pression=pression; meteoItem.humidite=humidity;
meteoItem.date=dateString;
meteoItem.image=weather.getJSONObject(0).getString("main");
meteoItems.add(meteoItem);
data.add(meteoItem);
}
model.notifyDataSetChanged();
} catch (JSONException e) {
e.printStackTrace();
}
}
},
MainActivity.java
new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
Log.i("MyLog","Connection problem!");
}
});
// Add the request to the RequestQueue.
queue.add(stringRequest);
}
});
}
}
MeteoItem.java
package net.youssfi.httpandroidapp;
import java.util.Date;
public class MeteoItem {
public int tempMax;
public int tempMin;
public int pression;
public int humidite;
public String image;
public String date;
}
MeteoListModel.java
package net.youssfi.httpandroidapp;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView; import android.widget.TextView;
import java.util.HashMap; import java.util.List;
import java.util.Map;
MeteoListModel.java
public class MeteoListModel extends ArrayAdapter<MeteoItem> {
private List<MeteoItem> listItems; private int resource;
public static Map<String,Integer> images=new HashMap<>();
static{
images.put("Clear",R.drawable.clear);
images.put("Clouds",R.drawable.clouds);
images.put("Rain",R.drawable.rain);
images.put("thunderstormspng",R.drawable.thunderstormspng);
}
public MeteoListModel(@NonNull Context context,int resource,
List<MeteoItem> data) {
super(context, resource,data);
Log.i("Size:",String.valueOf(data.size()));
this.listItems=data; this.resource=resource;
}
MeteoListModel.java
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup
parent) {
Log.i("MyLog","......................."+position);
View listItem=convertView;
if(listItem==null)
listItem =LayoutInflater.from(getContext()).inflate(resource,parent,false);
ImageView imageView=listItem.findViewById(R.id.imageView);
TextView textViewTempMax=listItem.findViewById(R.id.textViewTempMAX);
TextView textViewTempMin=listItem.findViewById(R.id.textViewTempMin);
TextView textViewPression=listItem.findViewById(R.id.textViewPression);
TextView textViewHumidite=listItem.findViewById(R.id.textViewHumidite);
TextView textViewDate=listItem.findViewById(R.id.textViewDate);
String key=listItems.get(position).image;
MeteoListModel.java
if(key!=null) imageView.setImageResource(images.get(key));
textViewTempMax.setText(String.valueOf(listItems.get(position).tempMax)+" °C");
textViewTempMin.setText(String.valueOf(listItems.get(position).tempMin)+" °C");
textViewPression.setText(String.valueOf(listItems.get(position).pression)+" hPa");
textViewHumidite.setText(String.valueOf(listItems.get(position).humidite)+" %");
textViewDate.setText(String.valueOf(listItems.get(position).date));
return listItem;
}
}
Android REST avec Retrofit : Application Github Users and Repositories Mobile App

L’objectif étant de créer une simple application mobile


Android qui permet de :
• Chercher les utilisateurs de Git Hub et les afficher dans
un ListView
• Afficher les repositories d’un utilisateur sélectionné
L’application montre comment :
• Interagir avec une Rest API en utilisant la librairie
RETROFIT
• Comment créer un modèle personnalisé de ListView
• Naviguer entre les activités
Dépendances du Projet : build.gradle

apply plugin: 'com.android.application' dependencies {

android { // https://mvnrepository.com/artifact/com.squareup.retrofit2/retrofit
compileSdkVersion 29 implementation group: 'com.squareup.retrofit2', name: 'retrofit', version: '2.9.0'
buildToolsVersion "29.0.3" // https://mvnrepository.com/artifact/com.squareup.retrofit2/converter-gson
implementation group: 'com.squareup.retrofit2', name: 'converter-gson', version: '2.9.0'
defaultConfig { // https://mvnrepository.com/artifact/de.hdodenhof/circleimageview
minSdkVersion 26 implementation group: 'de.hdodenhof', name: 'circleimageview', version: '2.2.0'
targetSdkVersion 29
} implementation fileTree(dir: 'libs', include: ['*.jar'])

buildTypes { implementation 'androidx.appcompat:appcompat:1.2.0'


release { implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
} testImplementation 'junit:junit:4.12'
} androidTestImplementation 'androidx.test.ext:junit:1.1.2'
compileOptions { androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
sourceCompatibility = 1.8 }
targetCompatibility = 1.8
}

}
AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>


<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="net.youssfi.gitapp">
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />


</intent-filter>
</activity>
<activity android:name=".RepositoryActivity" android:parentActivityName=".MainActivity"></activity>
</application>

</manifest>
API RESTFUL GITHUB https://api.github.com/users/mohamedYoussfi/repos

https://api.github.com/search/users?q=youssfi&per_page=5&page=0
package net.youssfi.gitapp.model;

public class GitRepo {


Modèle et Retrofit Service public int id;
public String name;
public int size;
public String language;
package net.youssfi.gitapp.model; }

import com.google.gson.annotations.SerializedName;

public class GitUser {


public int id;
public String login; package net.youssfi.gitapp.service;
@SerializedName("avatar_url")
public String avatarUrl; import net.youssfi.gitapp.model.GitRepo;
public int score; import net.youssfi.gitapp.model.GitUsersResponse;
}
import java.util.List;

package net.youssfi.gitapp.model; import retrofit2.Call;


import retrofit2.http.GET;
import com.google.gson.annotations.SerializedName; import retrofit2.http.Path;
import retrofit2.http.Query;
import java.util.ArrayList;
import java.util.List; public interface GitRepoServiceAPI {
public class GitUsersResponse {
@GET("search/users")
@SerializedName("total_count") public Call<GitUsersResponse> searchUsers(@Query("q") String query);
public int totalCount; @GET("users/{u}/repos")
@SerializedName("items") public Call<List<GitRepo>> userRepositories(@Path("u") String login);
public List<GitUser> users=new ArrayList<>(); }
}
ListView Model

public class UsersListViewModel extends ArrayAdapter<GitUser> {


private int resource;
public UsersListViewModel(@NonNull Context context, int resource, List<GitUser> data) {
super(context, resource,data);this.resource=resource;
}
@NonNull
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
View listViewItem=convertView;
if(listViewItem==null){
listViewItem= LayoutInflater.from(getContext()).inflate(resource,parent,false);
}
CircleImageView imageViewUser=listViewItem.findViewById(R.id.imageViewUser);
TextView textViewLogin=listViewItem.findViewById(R.id.textViewLogin);
TextView textViewScore=listViewItem.findViewById(R.id.textViewScore);
textViewLogin.setText(getItem(position).login);
textViewScore.setText(String.valueOf(getItem(position).score));
try {
URL url=new URL(getItem(position).avatarUrl);
Bitmap bitmap= BitmapFactory.decodeStream(url.openStream());
imageViewUser.setImageBitmap(bitmap);
} catch (Exception e) {
e.printStackTrace();
}
//imageViewUser.setImageBitmap();
return listViewItem;
}
}
MainActivity.java

public class MainActivity extends AppCompatActivity {


List<GitUser> data=new ArrayList<>();
public static final String USER_LOGIN_PARAM="user.login";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
final EditText editTextQuery=findViewById(R.id.editTextQuery);
Button buttonSearch=findViewById(R.id.buttonSearch);
ListView listViewUsers=findViewById(R.id.listViewUsers);
//final ArrayAdapter<String> arrayAdapter=new
ArrayAdapter<>(this,android.R.layout.simple_list_item_1,data);
UsersListViewModel listViewModel=new UsersListViewModel(this,R.layout.users_list_view_layout,data);
listViewUsers.setAdapter(listViewModel);
MainActivity.java : Retrofit
final Retrofit retrofit=new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
buttonSearch.setOnClickListener(v -> {
String query=editTextQuery.getText().toString();
Log.i("",query);
final GitRepoServiceAPI gitRepoServiceAPI=retrofit.create(GitRepoServiceAPI.class);
Call<GitUsersResponse> callGitUsers=gitRepoServiceAPI.searchUsers(query);
callGitUsers.enqueue(new Callback<GitUsersResponse>() {
@Override
public void onResponse(Call<GitUsersResponse> call, Response<GitUsersResponse> response) {
Log.i("info",call.request().url().toString());
if(!response.isSuccessful()){
Log.i("info",String.valueOf(response.code())); return;
}
GitUsersResponse gitUsersResponse=response.body();
data.clear();
for (GitUser user:gitUsersResponse.users){
data.add(user);
}
listViewModel.notifyDataSetChanged();
}
@Override
public void onFailure(Call<GitUsersResponse> call, Throwable t) { Log.e("error","Error");}
});
});
MainActivity.java

listViewUsers.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
String login=data.get(position).login;
Log.i("info",login);
Intent intent=new Intent(getApplicationContext(),RepositoryActivity.class);
intent.putExtra(USER_LOGIN_PARAM,login);
startActivity(intent);
}
});

}
}
RepositoryActivity

public class RepositoryActivity extends AppCompatActivity {


List<String> data=new ArrayList<>();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.repository_layout);
Intent intent=getIntent();
String login=intent.getStringExtra(MainActivity.USER_LOGIN_PARAM);
setTitle("Repositories");
TextView textViewLogin=findViewById(R.id.textViewUserLogin);
ListView listViewRepositories=findViewById(R.id.listViewRepositories);
ArrayAdapter<String> arrayAdapter=new ArrayAdapter<>(this,android.R.layout.simple_list_item_1,data);
listViewRepositories.setAdapter(arrayAdapter);
textViewLogin.setText(login);
RepositoryActivity
Retrofit retrofit=new Retrofit.Builder()
.baseUrl("https://api.github.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
GitRepoServiceAPI gitRepoServiceAPI=retrofit.create(GitRepoServiceAPI.class);
Call<List<GitRepo>> reposCall=gitRepoServiceAPI.userRepositories(login);
reposCall.enqueue(new Callback<List<GitRepo>>() {
@Override
public void onResponse(Call<List<GitRepo>> call, Response<List<GitRepo>> response) {
if(!response.isSuccessful()){
Log.e("error",String.valueOf(response.code()));
return;
}
List<GitRepo> gitRepos=response.body();
for(GitRepo gitRepo:gitRepos){
String content="";
content+=gitRepo.id+"\n"; content+=gitRepo.name+"\n";
content+=gitRepo.language+"\n"; content+=gitRepo.size+"\n";
data.add(content);
}
arrayAdapter.notifyDataSetChanged();
}
@Override
public void onFailure(Call<List<GitRepo>> call, Throwable t) { }
});
}
}
users_list_view_item-layout.xml
activity_main.xml <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
<?xml version="1.0" encoding="utf-8"?>
android:layout_width="match_parent"
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="match_parent">
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
<de.hdodenhof.circleimageview.CircleImageView
android:layout_height="match_parent"
android:id="@+id/imageViewUser"
android:orientation="vertical"
android:layout_width="100dp"
android:padding="10dp"
android:layout_height="100dp"
tools:context=".MainActivity" >
android:layout_weight="1"
app:srcCompat="@drawable/ic_launcher_background" />
<EditText
android:id="@+id/editTextQuery"
<LinearLayout
android:layout_width="match_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
android:ems="10"
android:layout_weight="1"
android:layout_margin="10dp"
android:padding="10dp"
android:padding="10dp"
android:layout_margin="10dp"
android:inputType="textPersonName"
android:orientation="vertical">
android:background="@drawable/edit_text_style1"
android:text="" />
<TextView
android:id="@+id/textViewLogin"
<Button
android:layout_margin="4dp"
android:id="@+id/buttonSearch"
android:layout_width="match_parent"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:layout_margin="10dp"
android:textSize="18dp"
android:background="@color/colorPrimary"
/>
android:textColor="@color/white"
android:text="Search" />
<TextView
android:id="@+id/textViewScore"
<ListView
android:layout_margin="4dp"
android:id="@+id/listViewUsers"
android:layout_width="match_parent"
android:layout_margin="10dp"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:text=""
android:layout_height="match_parent" />
android:textSize="18dp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
Repository_layout.xml edit_text_style1.xml
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<item>
android:layout_width="match_parent"
<shape android:shape="rectangle">
android:layout_height="match_parent"
<stroke android:color="@color/colorPrimary"
android:padding="10dp"
android:width="1dp"></stroke>
android:orientation="vertical">
</shape>
</item>
<TextView
</selector>
android:id="@+id/textViewUserLogin"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@drawable/edit_text_style1"
android:textSize="22dp"
android:layout_margin="10dp"
android:textAlignment="center"
android:text="TextView" />

<ListView
android:id="@+id/listViewRepositories"
android:layout_margin="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>