PROGRAMMATION DE COMPOSANTS MOBILES (ANDROID) WIESLAW ZIELONKA WWW.IRIF.UNIV-PARIS-DIDEROT.FR/~ZIELONKA
Charger une image depuis internet et afficher dans ImageView public Bitmap loadimagefrominternet(string adr) { URL url = null; InputStream inputstream = null; try { url = new URL(adr); } catch (MalformedURLException e) { return null; try { final HttpURLConnection http = (HttpURLConnection) url.openconnection(); if (http.getresponsecode() == HttpURLConnection.HTTP_OK) { inputstream = http.getinputstream(); } catch (IOException e) { return null; return BitmapFactory.decodeStream(inputStream); }
Connexion internet La connexion HTTP donne InputStream. Donc les méthodes de traitement de fichiers s'appliquent. Si InputStream ouvert sur une image alors Bitmap BitmapFactory.decodeStream(InputStream) retourne un Bitmap. Pour afficher Bitmap dans ImageView: ImageView.setImageBitmap(Bitmap)
Les problèmes 1. C'est une mauvaise idée d'effectuer une longue opération dans le thread UI bloquage d'interface graphique. 2. De toute façon android ne permet pas de faire de connexion internet dans le thread principal. 3. Et enfin, pour une une connexion internet il faut une permission
Permission pour une connexion internet <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="fr.irif.zielonka.loadimageinternet"> <uses-permission android:name="android.permission.internet"/> <application > <activity android:name=".imagefrominternetactivity"> <intent-filter> <action android:name="android.intent.action.main" /> <category android:name="android.intent.category.launcher" /> </intent-filter> </activity> </application> </manifest> Ajouter la permission dans le fichier Manifest.
La connexion internet dans un autre thread protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_image_from_internet); final ImageView imageview = (ImageView) findviewbyid(r.id.image_view); String s = getresources().getstring(r.string.animal); new Thread(new Runnable() { @Override public void run() { Bitmap bitmap = loadimagefrominternet(s); imageview.setimagebitmap(bitmap); } }).start(); Non! Il ne faut jamais manipuler l'interface graphique depuis un autre thread que le thread principal.
Faire une opération sur l'interface graphique depuis un autre thread Android offre trois méthodes pour accéder au thread principal depuis un autre thread: Activity.runOnUiThread(Runnable) View.post(Runnable) view.postdelayed(runnable, long)
Faire une opration sur l'interface graphique depuis un autre thread protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_image_from_internet); final ImageView imageview = (ImageView) findviewbyid(r.id.image_view); String s = getresources().getstring(r.string.animal); new Thread(new Runnable() {//nouveau thread @Override public void run() { Bitmap bitmap = loadimagefrominternet(s); runonuithread(new Runnable() { @Override public void run() { imageview.setimagebitmap(bitmap); } }); } }).start();
Handlers Chaque thread possède un MessageQueue. On crée un Handler dans un thread A. En utilisant ce handler un autre thread peut envoyer vers le thread A des messages (avec de données) et des Runable (pour exécuter par A).
Handlers thread A thread B MessageQueue de A Handler Message Runnable
Méthodes de Handler post(runnable) postattime(runnable, long) postdelayed(runnable, long) sendemptymessage(int) sendmessage(message) sendmessageattime(message, long) sendmessagedelayed(message, long) Les Messages et Runnables sont mis sur la file MessageQueue du thread A. Les Runnables sont exécutés par le thread A. Les messages sont transmis à la méthode handlemessage(message) de Handler. Donc pour traiter les massages il faut implementer cette méthode dans Handler.
Création de Handler Le Handler pour le thread A doit être créé par le thread A lui même.
Même exemple avec un Handler protected void oncreate(bundle savedinstancestate) { animals = getresources().getstringarray(r.array.animals); final CustomAdapter adapter = new CustomAdapter(this); listview.setadapter(adapter); handler = new Handler(); new Thread(new Runnable() { @Override public void run() { for (String s : animals) { final Bitmap bitmap = loadimagefrominternet(s); handler.post(new Runnable() { @Override public void run() { adapter.add(bitmap); }); }).start();
AsyncTask AsyncTask permet d'automatiser l'exécution de tâche en arrière plan (c'est-à-dire dans un thread différent du thread principal). Faire implémenter une classe dérivée de AsyncTask classe paramétrée. AsyncTask<Params, Progress, Result> Params le type de l'entrée Progress- le type pour mesurer l'avancement de la tâche Result le type de résultat
AsyncTask protected Result doinbackground(params params) méthode exécutée en background par un autre thread. Vous devez implementez cette méthode.les threads de ackground sont créés par AsyncTask, vous ne devez pas créer de thread vous même. Vous pouvez implémenter: protected void onpreexecute() protected void onpostexecute(result result) les méthodes exécutées dans le thread UI avant et après doinbackground()
AsyncTask protected final void publishprogres(progres progres) Vous pouvez appeler cette méthode dans doinbackground() pour signaler le progrès de l'exécution de la tâche. protected void onprogresupdate(progress ) est appelée par UI thread suite à l'appel de publishprogres() execute(params params) exécuter la tâche avec les paramètres params
AsyncTask animals = getresources().getstringarray(r.array.animals); final CustomAdapter adapter = new CustomAdapter(this); listview.setadapter(adapter); class Task extends AsyncTask<String[], Integer, ArrayList<Bitmap>> { @Override protected ArrayList<Bitmap> doinbackground(string[]... strings) { ArrayList<Bitmap> al = new ArrayList<>(); for (String s : strings[0]) { al.add(loadimagefrominternet(s)); return al; @Override protected void onpostexecute(arraylist<bitmap> bitmaps) { super.onpostexecute(bitmaps); adapter.add(bitmaps); new Task().execute(animals);
CustomAdapter static class CustomAdapter extends BaseAdapter { Context context; ArrayList<Bitmap> images; public CustomAdapter(Context context) { this.context = context; images = new ArrayList<>(); public void add(arraylist<bitmap> bitmap) { images.addall(bitmap); notifydatasetchanged();/* pour que la liste affiche de nouveau element */ @Override public View getview(int i, View view, ViewGroup viewgroup) { if (view == null) { LayoutInflater minflater = (LayoutInflater) context.getsystemservice(activity.layout_inflater_service); view = minflater.inflate(r.layout.list_item, viewgroup, false); ((ImageView) view).setimagebitmap(images.get(i)); return view;
CustomAdapter } @Override public int getcount() { return images.size(); @Override public Object getitem(int i) { return images.get(i); @Override public long getitemid(int i) { return (long) i;