Introduction à Android

Post on 02-Jul-2015

613 views 0 download

description

Support de cours sur les bases du développement Android

Transcript of Introduction à Android

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[{"imac2011@googlegroups.com"});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• …