Programmation Mobile Android Master CCI Bertrand Estellon Aix-Marseille Université March 23, 2015 Bertrand Estellon (AMU) Android Master CCI March 23, 2015 1 / 266 Les fichiers Deux espaces de stockage : Stockage interne : Toujours disponible Par défaut, accessible uniquement par votre application Supprimés à la désinstallation de l application Sockage externe : Pas toujours disponible (USB, etc) Accessibles et modifiables par tout le monde Seuls les fichiers du répertoire getexternalfilesdir() sont supprimés à la désinstallation de l application Nécessite des permissions Utile pour partager des données entre applications Bertrand Estellon (AMU) Android Master CCI March 23, 2015 172 / 266 Créer un fichier dans le stockage interne Deux répertoires : getfilesdir() : Le répertoire interne de votre application ; getcachedir() : le cache interne de votre application Pour créer un fichier dans l un de ces répertoires : File file = new File(contextgetFilesDir(), "fichiertxt"); ou FileOutputStream outputstream = openfileoutput("fichiertxt", ContextMODE_PRIVATE); ou File file = FilecreateTempFile("fichier", "tmp", contextgetcachedir()); Bertrand Estellon (AMU) Android Master CCI March 23, 2015 173 / 266 Nous souhaitons écrire un éditeur de fichier : Bertrand Estellon (AMU) Android Master CCI March 23, 2015 174 / 266
Déclenchement de l écriture et de la lecture du fichier : Supposons que nous ayons l activité suivante : public class MainActivity extends Activity { private EditText edittext; protected void oncreate(bundle savedinstancestate) { superoncreate(savedinstancestate); setcontentview(rlayoutactivity_main); edittext = (EditText)findViewById(RideditText); public class MainActivity extends Activity { private EditText edittext; protected void onstart() { superonresume(); edittextsettext(load()); protected void onstop() { superonpause(); save(edittextgettext()tostring()); Bertrand Estellon (AMU) Android Master CCI March 23, 2015 175 / 266 Bertrand Estellon (AMU) Android Master CCI March 23, 2015 176 / 266 La sauvegarde : private void save(string string) { File file = new File(getFilesDir(), filename); try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { writerwrite(string); catch (IOException e) { ToastmakeText(this, getstring(rstringread_error), ToastLENGTH_LONG); La lecture : private String load() { File file = new File(getFilesDir(), filename); if (!fileexists()) return ""; try (BufferedReader reader = new BufferedReader(new FileReader(file))) { return load(reader); catch (IOException e) { ToastmakeText(this, getstring(rstringread_error), ToastLENGTH_LONG); return ""; Bertrand Estellon (AMU) Android Master CCI March 23, 2015 177 / 266 Bertrand Estellon (AMU) Android Master CCI March 23, 2015 178 / 266
Permissions pour le stockage externe La lecture : private String load(bufferedreader reader) throws IOException { StringBuilder builder = new StringBuilder(); for(;;) { String line = readerreadline(); if (line==null) break; builderappend(line)append("\n"); return buildertostring(); Il suffit d ajouter les permissions dans le manifeste de l application : Pour l écriture : <manifest> <uses-permission android:name="androidpermissionwrite_external_storage" /> </manifest> Pour la lecture : <manifest> <uses-permission android:name="androidpermissionread_external_storage" /> </manifest> Bertrand Estellon (AMU) Android Master CCI March 23, 2015 179 / 266 Un exemple d application Nous souhaitons parcourir et lire les fichiers du stockage externe : Bertrand Estellon (AMU) Android Master CCI March 23, 2015 180 / 266 Un exemple d application Nous souhaitons parcourir et lire les fichiers du stockage externe : Deux types de fragments : Affichage d un répertoire : DirectoryFragment; Deux types de fragments : Affichage d un répertoire : DirectoryFragment; : FileFragment : FileFragment Bertrand Estellon (AMU) Android Master CCI March 23, 2015 181 / 266 Bertrand Estellon (AMU) Android Master CCI March 23, 2015 182 / 266
Le layout : <FrameLayout xmlns:android="" android:layout_width="match_parent" android:layout_height="match_parent"> <ScrollView android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:id="@+id/textview"/> </ScrollView> </FrameLayout> Création de l instance et conservation du chemin : public class FileFragment extends Fragment { public static FileFragment newinstance(string filename) { FileFragment fragment = new FileFragment(); Bundle args = new Bundle(); argsputstring("path", filename); fragmentsetarguments(args); return fragment; private String path() { return getarguments()getstring("path"); Bertrand Estellon (AMU) Android Master CCI March 23, 2015 183 / 266 Création de la vue et gestion du cycle de vie : public class FileFragment extends Fragment { private TextView textview; public View oncreateview(layoutinflater inflater, ViewGroup container, Bundle savedinstancestate) { View view = inflaterinflate(rlayoutfragment_file, container, false); textview = (TextView)viewfindViewById(RidtextView); return view; public void onresume() { superonresume(); textviewsettext(load()); getactivity()settitle(path()); Bertrand Estellon (AMU) Android Master CCI March 23, 2015 184 / 266 Chargement du contenu du fichier : public class FileFragment extends Fragment { private String load() { File file = new File(path()); if (!fileexists()) return ""; try (BufferedReader reader = new BufferedReader(new FileReader(file))) { return load(reader); catch (IOException e) { ToastmakeText(thisgetActivity(), getstring(rstringread_error), ToastLENGTH_LONG); return ""; Bertrand Estellon (AMU) Android Master CCI March 23, 2015 185 / 266 Bertrand Estellon (AMU) Android Master CCI March 23, 2015 186 / 266
Chargement du contenu du fichier : public class FileFragment extends Fragment { private String load(bufferedreader reader) throws IOException { StringBuilder builder = new StringBuilder(); for(;;) { String line = readerreadline(); if (line==null) break; builderappend(line)append("\n"); return buildertostring(); Création de l instance : public static DirectoryFragment newinstance(string path) { DirectoryFragment fragment = new DirectoryFragment(); Bundle args = new Bundle(); argsputstring("path", path); fragmentsetarguments(args); return fragment; private String path() {return getarguments()getstring("path"); Bertrand Estellon (AMU) Android Master CCI March 23, 2015 187 / 266 Bertrand Estellon (AMU) Android Master CCI March 23, 2015 188 / 266 Création de la vue et gestion du cycle de vie : private String[] files; void oncreate(bundle savedinstancestate) { superoncreate(savedinstancestate); File directory = new File(path()); files = directorylist(); setlistadapter(new ArrayAdapter<>(getActivity(), androidrlayoutsimple_list_item_1, androidridtext1, files)); Mise en place des notifications de l activité : private OnDirectoryFragmentListener listener; public interface OnDirectoryFragmentListener { public void onchangepath(string path); public void onresume() { superonresume(); getactivity()settitle(path()); Bertrand Estellon (AMU) Android Master CCI March 23, 2015 189 / 266 Bertrand Estellon (AMU) Android Master CCI March 23, 2015 190 / 266
Mise en place des notifications de l activité : private OnDirectoryFragmentListener listener; public void onattach(activity activity) { superonattach(activity); try { listener = (OnDirectoryFragmentListener) activity; catch (ClassCastException e) { throw new ClassCastException(activitytoString() + " must implement OnFragmentInteractionListener"); public void ondetach() { superondetach(); listener = null; Mise en place des notifications de l activité : private OnDirectoryFragmentListener listener; public void onlistitemclick(listview list, View view, int position, long id) { superonlistitemclick(list, view, position, id); if (null!= listener) { String path = path()equals("/")?"":path(); listeneronchangepath(path + "/" + files[position]); Bertrand Estellon (AMU) Android Master CCI March 23, 2015 191 / 266 L activité principale Bertrand Estellon (AMU) Android Master CCI March 23, 2015 192 / 266 L activité principale Réception des notifications des fragments : Création de le la vue : public class MainActivity extends Activity { protected void oncreate(bundle savedinstancestate) { superoncreate(savedinstancestate); setcontentview(rlayoutactivity_main); if (savedinstancestate == null) { getfragmentmanager()begintransaction() add(ridcontainer, DirectoryFragmentnewInstance("/")) commit(); public class MainActivity extends Activity implements DirectoryFragmentOnDirectoryFragmentListener { public void onchangepath(string path) { File file = new File(path); Fragment fragment = (fileisdirectory())?directoryfragmentnewinstance(path) :FileFragmentnewInstance(path); getfragmentmanager()begintransaction() replace(ridcontainer, fragment) addtobackstack(path) commit(); Bertrand Estellon (AMU) Android Master CCI March 23, 2015 193 / 266 Bertrand Estellon (AMU) Android Master CCI March 23, 2015 194 / 266
Le format JSON Le format JSON JSON (JavaScript Oject Notation) est un format de données dérivé de la notation des objets et tableaux de ECMAScript (donc de JavaScript) : {"machin": { "taille": 12, "style": "gras", "bidule": { "machin": [ {"style" : "italique", {"style" : "gras" ] L avantage de JSON est qu il est reconnu nativement par JavaScript Les éléments en JSON : Les objets : {chaîne : valeur, chaîne : valeur Les tableaux : [valeur, valeur, ] Les valeurs : chaîne, nombre, objet, tableau, true, false, null Les chaînes : "abcdef" ou "abcd\n\t" Les nombres : -123412 {"unobjet": { "untableau": [12, 13, 53], "unnombre" : 53, "unchaîne" : "truc\n" "unobjet" : { "style" : "gras" Bertrand Estellon (AMU) Android Master CCI March 23, 2015 195 / 266 Le format JSON Bertrand Estellon (AMU) Android Master CCI March 23, 2015 196 / 266 Les éléments en JSON : Les objets : {chaîne : valeur, chaîne : valeur Les tableaux : [valeur, valeur, ] Les valeurs : chaîne, nombre, objet, tableau, true, false, null Les chaînes : "abcdef" ou "abcd\n\t" Les nombres : -123412 {"unobjet": { "untableau": [12, 13, 53], "unnombre" : 53, "unchaîne" : "truc\n" "unobjet" : { "style" : "gras" La gestion des objets est réalisée par la classe JSONObject : JSONObject put(string key, JSONObject object) ; JSONObject put(string key, JSONArray array) ; JSONObject put(string key, boolean int long double b) ; JSONObject getjsonobject(string key) ; JSONArray getjsonarray(string key) ; boolean getboolean(string key), ; Bertrand Estellon (AMU) Android Master CCI March 23, 2015 197 / 266 Bertrand Estellon (AMU) Android Master CCI March 23, 2015 198 / 266
Un objet JSON : La gestion des tableaux est réalisée par la classe JSONArray : JSONArray put([int index,] JSONObject object) ; JSONArray put([int index,] JSONArray array) ; JSONArray put([int index,] boolean int long double b) ; JSONObject getjsonobject(int index) ; JSONArray getjsonarray(int index) ; boolean getboolean(int index), ; int length() ; {"array": [1, 2, 3], "boolean" : false Construction d une chaîne de caractères au format JSON en Java : String tojson() throws JSONException { JSONObject object = new JSONObject(); JSONArray array = new JSONArray(); arrayput(1)put(2)put(3); objectput("array", array); objectput("boolean", false); return objecttostring(); Bertrand Estellon (AMU) Android Master CCI March 23, 2015 199 / 266 Bertrand Estellon (AMU) Android Master CCI March 23, 2015 200 / 266 Un objet JSON : {"array": [1, 2, 3], "boolean" : false Construction d une chaîne de caractères au format JSON en Java : String tojson() throws JSONException { JSONObject object = new JSONObject(); JSONArray array = new JSONArray(); arrayput(1)put(2)put(3); objectput("array", array); objectput("boolean", false); return objecttostring(); Un objet JSON : {"array": [1, 2, 3], "boolean" : false Lecture d une chaîne de caractères au format JSON en Java : void readjson(string json) throws JSONException { JSONObject object = new JSONObject(json); JSONArray array = objectgetjsonarray("array"); for (int i = 0; i < arraylength(); i++) Logd("json", ""+arrayget(i)); Logd("json", ""+objectgetboolean("boolean")); Bertrand Estellon (AMU) Android Master CCI March 23, 2015 201 / 266 Bertrand Estellon (AMU) Android Master CCI March 23, 2015 202 / 266