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
Flutter Widgets
Web View Cupertino
Material Design
HTML Native
CSS ARM
Java Binary
Script Code
Platform
Channels
• 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
• 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
• 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.
• 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.
• https://www.oracle.com/technetwork/java/javase/downloa
ds/jdk8-downloads-2133151.html
• https://developer.android.com/studio#downloads
SDK Manager
• Next
• Next
• Next
• Finish
Java
Android SDK
Android Studio
• Etc..
• Dossier Java :
• 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
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…)
...
}
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
}
}
activity_main.xml
Hello World
Java
Android SDK
Android Studio
Hello World
• En exécutant l’application, vous faites appel à Graddle pour recompiler et construire 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
Ressources String.xml
<resources>
<string name="app_name">MyFirstMobileApp</string>
<string name="label_message">Hello Word</string>
</resources>
Java
Android SDK
Android Studio
Ressources
<resources>
<string name="app_name">MyFirstMobileApp</string>
<string name="label_message">Hello Word</string>
</resources>
Java
Android SDK
Android Studio
Ressources
Ressources
Autres ressources
L’objectif étant de créer une simple application mobile Android qui permet de :
<resources> values.xml
<string name="app_name">First App</string>
<string name="hw">Hello BDCC</string>
</resources>
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;
@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
• BRAVO
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;
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
}
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
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>
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
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'])
}
AndroidManifest.xml
</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;
import com.google.gson.annotations.SerializedName;
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
<ListView
android:id="@+id/listViewRepositories"
android:layout_margin="10dp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>