introduction à android
DESCRIPTION
Support de cours sur les bases du développement AndroidTRANSCRIPT
A propos
Yoann Gotthilf, CTO d’une startup et freelance Web/Mobile
• développeur Android depuis 6 ans• développeur Web depuis 13 ans• consultant sécurité pendant 6 ans• développeur Fullstack JS depuis 1 ans
yoann.gotthilf at gmail.com • @ygotthilf
Références
Site officiel http://developer.android.com
Blog officiel http://android-developers.blogspot.fr
Blog Romain Guy http://www.curious-creature.org/category/android
Blog Cyril Mottier (Fr + En) http://cyrilmottier.com
Qu'est ce qu'Android ?
Une plateforme unifiée pour terminaux mobiles(système d'exploitation + frameworks)
Ce n'est pas une distribution Linux.
Qui développe Android ?
Android est open source : il existe donc de nombreux forks (CyanogenMod, Amazon, ...)
Qui soutient Android ?
L'Open Handset Alliance : un consortium d'industriels créé par Google en 2007.
L'histoire sans grand H
1991, norme GSM (communication « voix ») 1992, IBM Simon (1er « smartphone ») 2005, startup Android racheté par Google 2007, lancement iPhone + forfait data « illimité » Sept. 2008, officialisation et publication SDK Oct. 2008, lancement du 1er smartphone Android
Le marché
Architecture Android 1/4
Architecture Android 2/4
Architecture Android 3/4
Architecture Android 4/4
Ou développer dans cette architecture ?
Uniquement sur la couche framework applicatif !Les développeurs tiers n'ont pas accès aux couches systèmes sous-jacentes.
IDE
Tester son application
3 méthodes :• Emulateur livré avec le SDK (pas terrible)• Emulateur Genymotion (pas mal)• Son smartphone (top)
La communication s’effectue grâce au ADB
Les versions• Courante : KitKat 4.4 (API 19)• Prochaine : L (API 20)
Répartition des versions
Gérer la fragmentation
Utiliser la librairie de supporthttp://developer.android.com/tools/support-library/index.html
Que contient une application ?
• Manifeste Android• Ressources • Classes Java (Dalvik ou ART)
• Librairies & JNI
Le livrable est un APK (Android Package)
AndroidManifest.xml
Permet au système de « connaître » l'application :• nom, logo et version• compatibilité (écran, version d'Android, …)• permissions• composants (activité, service, BR, CP)
Ressources Qu'est-ce ?
image fichier multimédia (musique, vidéo) layout (vue) style (couleur, marge, police, ...) animation internationalisation
Ressources L’organisation
Chaque type à son propre répertoire
Nom des fichiers : [a-z0-9_]+\.<extention>
Ressources Gérer la configuration 1/2
Comment gérer les ressources en fonction de la configuration de chaque terminal Android ?
C’ést-à-dire de la langue, taille d'écran, ratio d'écran, résolution, version d'Android, ...
Ressources Gérer la configuration 2/2
1. Le développeurclasse par répertoire les différentes configurations souhaitées
2. A l'exécution, Androidchoisit les bonnes ressources
Ressources Les valeurs 1/2
• chaîne de caractères (chaîne simple, tableau, pluriel)
• couleur• style• booléen• id• entier• tableau typé
Ressources Les valeurs 2/2
<?xml version="1.0" encoding="utf-8"?><resources>
<string name="app_name">My first app</string><string name="hello">Hello world</string>
<color name="primary_color">#ff33b5e5</color><color name="secondary_color">#df0000</color>
<string-array name="week_end_days"><item>Sunday</item><item>Saturday</item>
</string-array>
<dimen name="default_margin">2dp</dimen>
<bool name="test_mode">false</bool></resources>
Fichier res/values/all.xml
Ressources Exemple de layout
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical">
<TextViewandroid:text="@string/hello_world"android:layout_width="match_parent"android:layout_height="wrap_content"android:textColor="@color/primary_color"/>
<ImageViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:src="@drawable/ic_launcher"/>
</LinearLayout>
Fichier res/layout/main.xml
Ressources Accès depuis un XML
@<type>/<nom variable>
Exemples :• @string/hello_world• @drawable/icon• @color/primary_color
Ressources Accès depuis le code
imageView.setImageResource(R.drawable.icon);
textView.setText(R.string.hello_world);
aapt
package fr.imac.test;
public final class R {public static final class attr {}public static final class drawable {
public static final int icon=0x7f020000;}public static final class id {
public static final int hello_text=0x7f060000;}public static final class layout {
public static final int info=0x7f030000;public static final int main=0x7f030001;
}public static final class raw {
public static final int intra=0x7f040000;}public static final class string {
public static final int app_name=0x7f050000;public static final int hello_world=0x7f050001;
}}
Ressources prédéfinies
Le SDK Android propose des ressources prédéfiniesA manipuler comme les ressources du projet mais préfixé par Android.
android.R.string.ok@android:string/ok
La liste dans <Répertoire Android Studio>\sdk\platforms\android-<version>\data\res
Les composants UI
Déclarer une vue
Démo
Exécution d'application
Le système gère seul le cycle de vie des composants applicatifs.
Le système vous donne temporairement la main dans des méthodes de callback pour exécuter vos traitements.
Activité Qu’est ce ?
Une Activity réprésente un écran dans une application
Son rôle est d’afficher et de contrôler une seule vue
import android.os.Bundle;import android.support.v7.app.ActionBarActivity;import android.view.Menu;
public class MyActivity extends ActionBarActivity {
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);}
@Overrideprotected void onDestroy() {
super.onDestroy();// The activity is about to be destroyed.
}
@Overridepublic boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu;return true;
}}
Activité Cycle de vie
public class MyActivity extends ActionBarActivity {
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.activity_my);
}}
Activité Afficher une vue
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical">
<TextViewandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:textAppearance="?android:attr/textAppearanceMedium"android:text="@string/connection"android:layout_gravity="center_horizontal" />
<EditTextandroid:inputType="textEmailAddress"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/email"android:id="@+id/email" />
<EditTextandroid:inputType="textPassword"android:layout_width="match_parent"android:layout_height="wrap_content"android:hint="@string/password"android:id="@+id/password" />
<Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content" android:text="@android:string/ok"android:id="@+id/submit"/>
</LinearLayout>
public class MyActivity extends ActionBarActivity {
private EditText mEmailText ;
private EditText mPasswordText ;
private Button mSubmitButton ;
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.activity_my);
mEmailText = (EditText) findViewById(R.id.email);mPasswordText = (EditText) findViewById(R.id.password);mSubmitButton = (Button) findViewById(R.id.submit);
}
[...]
}
Activité Récupérer les composants graphiques
@Overrideprotected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);setContentView(R.layout.activity_my);
mEmailText = (EditText) findViewById(R.id.email);mPasswordText = (EditText) findViewById(R.id.password);mSubmitButton = (Button) findViewById(R.id.submit);
mSubmitButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View view) {
String email = mEmailText.getText().toString();System.out.println(email);
}});
}
Activité Intéraction
Activité Exemple
Démo
Fragment Problème
Layout list Layout message
Activity list Activity message
Layout inbox
Activity inbox
Affiche
Contrôle Contrôle
Affiche Affiche
Contrôle
Phone Tablet
Fragment Solution
Layout list Layout message
Activity main Activity detail
Phone Tablet
Contrôle Contrôle
Affiche Affiche
Fragment list Fragment message
LanceLance
Layout main
Fragment En détail
package fr.imac.uberconverter;
import android.app.Fragment;import android.os.Bundle;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.widget.EditText;
public class ExampleFragment extends Fragment {@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {// Inflate the layout for this fragmentreturn inflater.inflate(R.layout.fragment_main, container, false);
}
@Overridepublic void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
View parent=getView();
EditText celsius = (EditText) parent.findViewById(R.id.celsius);}
}
Fragment Chargement et manipulation
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"android:layout_width="match_parent"android:layout_height="match_parent"><fragment android:name="com.example.news.ArticleListFragment"
android:id="@+id/list"android:layout_weight="1"android:layout_width="0dp"android:layout_height="match_parent" />
<fragment android:name="com.example.news.ArticleReaderFragment"android:id="@+id/viewer"android:layout_weight="2"android:layout_width="0dp"android:layout_height="match_parent" />
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?><fragment xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/list"android:name="com.example.news.ArticleListFragment"android:layout_width="match_parent"android:layout_height="match_parent" />
res/layout-large/activity1.xml res/layout/activity1.xml
FragmentManager fragmentManager = getFragmentManager();FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ArticleReaderFragment fragment = new ArticleReaderFragment();fragmentTransaction.add(R.id.viewer, fragment);fragmentTransaction.commit();
Dans une activité
Fragment exemple
Démo
L'ActionBar
Depuis 3.0 Eléments :
Actions items Navigation Tabs Drop-down Navigation Navigation drawer Recherche Vue personnalisable
AdapterView présentation
Vue dont l’affichage des enfants est géré par un adaptateur
• Implémentations : ListView, GridView, Spinner, Gallery, …
• Optimisé pour l’affichage de beaucoup de vues :
• Construction à la volé d’une vue
• Réutilisation des vues inutilisés
AdapterView fonctionnement
AdapterViewAdapter
ListView GridViewListAdapter CursorAdapterBaseAdapter
Données
Layout
Utilise
Construit
Récupère
Hérite Hérite
AdapterView exemple ListView
public class List1 extends ListActivity {
@Overridepublic void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.list_1);ListAdapter adapter=new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, mStrings) ;
setListAdapter(adapter);}
private String[] mStrings = {"Abbaye de Belloc", "Abbaye du Mont des Cats", "Abertam", "Abondance", "Ackawi"
};
<TextView xmlns:android="http://schemas.android.com/apk/res/android"android:id="@android:id/text1"android:layout_width="match_parent"android:layout_height="wrap_content"android:textAppearance="?android:attr/textAppearanceListItemSmall"android:gravity="center_vertical"android:paddingStart="?android:attr/listPreferredItemPaddingStart"android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"android:minHeight="?android:attr/listPreferredItemHeightSmall"
/>
<LinearLayoutxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" >
<TextViewstyle="?android:attr/textAppearanceLarge"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="@string/cheeses" />
<ListViewandroid:id="@android:id/list"android:layout_width="match_parent"android:layout_height="match_parent" />
</LinearLayout>
res/layout/simple_list_item1.xml dans le sdkres/layout/list_1.xml
List1.java
Settings/Preferences
public class SettingsFragment extends PreferenceFragment {@Overridepublic void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resourceaddPreferencesFromResource(R.xml.preferences);
}...
}
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"><PreferenceCategory
android:title="@string/pref_sms_storage_title"android:key="pref_key_storage_settings"><CheckBoxPreference
android:key="pref_key_auto_delete"android:summary="@string/pref_summary_auto_delete"android:title="@string/pref_title_auto_delete"android:defaultValue="false"... />
<Preferenceandroid:key="pref_key_sms_delete_limit"android:dependency="pref_key_auto_delete"android:summary="@string/pref_summary_delete_limit"android:title="@string/pref_title_sms_delete"... />
<Preferenceandroid:key="pref_key_mms_delete_limit"android:dependency="pref_key_auto_delete"android:summary="@string/pref_summary_delete_limit"android:title="@string/pref_title_mms_delete" ... />
</PreferenceCategory>...
</PreferenceScreen>
Autres vues spécifiques
• Boîte de dialogue• Toast• Notification
Composants principaux
• Activity : gestion du cycle de vie d'une vue• Service : traitement en tâche de fond • BroadcastReceiver : traitement événementiel• ContentProvider : partage de données inter-
application
• Intent : canal de communication entre composants et applications
Sandbox
Chaque application à :• son UID et GUID• son processus et sa VM • son répertoire protégé
Une permission dans le manifeste :• doit être validé par l'utilisateur à l'installation• attribut un GUID à l'application
Service IPC : via le Binder (Intent, AIDL)
Service
Lancer des opérations en arrière plan sans interface graphique et indépendamment de l’utilisation de l’application
Intent présentation
Message pour lancer une action d’un composant
Intent envoie
Intent intent = new Intent();intent.setAction(Intent.ACTION_VIEW);intent.setData(Uri.parse("http://www.youtube.com/watch?v=iwsqFR5bh6Q"));
context.startActivity(intent);
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);context.startActivityForResult(takePictureIntent, 1);
Intent i=new Intent(Intent.ACTION_SEND);i.putExtra(Intent.EXTRA_EMAIL, new String[{"[email protected]"});i.putExtra(Intent.EXTRA_TEXT, "Ca avance le projet ?");Intent i2=Intent.createChooser(i, "Choisir...");context.startActivity(i2);
context.startActivity(new Intent(context, SettingsActivity.class));
context.startService(new Intent(context, CurrencyService.class));
Implicite
Explicite
Intent réception
<receiver android:name=".CurrencyReceiver" ><intent-filter>
<action android:name="android.intent.action.TIMEZONE_CHANGED"/><action android:name="android.intent.action.ACTION_BOOT_COMPLETED"/>
</intent-filter></receiver>
<activity android:name=".YouTubeActivityActivity" ><intent-filter>
<action android:name="android.intent.action.VIEW" />
<dataandroid:host="www.youtube.com"android:scheme="http" />
</intent-filter></activity>
Intent filter dans le manifeste
BroadcastReceiver<receiver
android:name=".MySMSReceiver"><intent-filter android:priority="100" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" /></intent-filter>
</receiver>
public class MySMSReceiver extends BroadcastReceiver {
private final String ACTION_RECEIVE_SMS = "android.provider.Telephony.SMS_RECEIVED";
@Overridepublic void onReceive(Context context, Intent intent) {
if (intent.getAction().equals(ACTION_RECEIVE_SMS)) {Bundle bundle = intent.getExtras();if (bundle != null) {
Object[] pdus = (Object[]) bundle.get("pdus");
final SmsMessage[] messages = new SmsMessage[pdus.length];for (int i = 0; i < pdus.length; i++) {
messages[i] = SmsMessage.createFromPdu((byte[]) pdus[i]);}if (messages.length > -1) {
final String messageBody = messages[0].getMessageBody();final String phoneNumber = messages[0]
.getDisplayOriginatingAddress();
Toast.makeText(context, "Expediteur : " + phoneNumber,Toast.LENGTH_LONG).show();
Toast.makeText(context, "Message : " + messageBody,Toast.LENGTH_LONG).show();
}}
}}
}
Persistance des données
5 méthodes :• Le stockage externe (données publiques)• Le stockage interne• Les préférences• La base de données privée SQLite• La connexion réseau
Testing
• Test unitaire (JUnit)• Test d’interface utilisateur• Mock• …