Android : uploader une image sur un serveur web
Une petite Mise à jour : pour écrire l’image pour envoi : utilisation de Bitmap.compress !
Ultra plus rapide !!!!
Un petit tuto pour apprendre à uploader une image (jpg ou autre) depuis votre application android vers un serveur web.
Pour ce genre de tâche qui peut être longue, Android conseille d’implémenter un Service plutôt qu’une activité : un service tourne en tâche de fond et ne bloque pas l’application.
Pour ce tuto :
- créez une nouvelle application TutoUpload et une classe TutoUpload.
- créez ensuite une deuxième classe HttpUploader
- n’oubliez pas de déclarer ces classes dans le Manifest et d’ajouter la permission internet pour l’application
- créez le fichier main.xml pour la layout de la classe TutoUpload
Le code de la classe TutoUpload :
package com.test.upload;
import java.io.File;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class TutoUpload extends Activity {
protected Uri image=null; //acces au fichier via contentResolver
File fichier; //le fichier à uploader
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//un bouton pour envoi du fichier vers le serveur
final Button validbutton = (Button) findViewById(R.id.send);
validbutton.setOnClickListener(send_listener);
}
//pour valider tout pour envoi vers site web
OnClickListener send_listener = new OnClickListener() {
public void onClick(View v) {
image = Uri.fromFile(fichier);
Intent uploadIntent = new Intent( );
uploadIntent.setClassName("com.test.upload", "com.test.upload.HttpUploader");
uploadIntent.setData(image);
startService(uploadIntent);
}
};
@Override
protected void onPause() {
super.onPause();
}
@Override
protected void onStop() {
Log.i(getClass().getSimpleName(),"on stop");
super.onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
Le code du service HttpUploader
package com.test.upload;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import android.app.Service;
import android.content.ContentResolver;
import android.content.Intent;
import android.provider.MediaStore;
import android.database.Cursor;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.widget.Toast;
public class HttpUploader extends Service {
private Intent mInvokeIntent;
private volatile Looper mUploadLooper;
private volatile ServiceHandler mUploadHandler;
private int check = 0;
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
//get extra datas
Uri selectedImg = (Uri)msg.obj;
Log.i(getClass().getSimpleName(),"selectedImg =" + selectedImg);
//upload the file to the web server
doHttpUpload(selectedImg);
Log.i(getClass().getSimpleName(), "Message: " + msg);
Log.i(getClass().getSimpleName(), "Done with #" + msg.arg1);
stopSelf(msg.arg1);
}
};
// Method called when (an instance of) the Service is created
public void onCreate() {
Log.i(getClass().getSimpleName(),"HttpUploader on create");
// This is who should be launched if the user selects our persistent
// notification.
mInvokeIntent = new Intent();
mInvokeIntent.setClassName("com.test.upload", "com.test.upload.HttpUploader");
// Start up the thread running the service. Note that we create a
// separate thread because the service normally runs in the process's
// main thread, which we don't want to block.
HandlerThread thread = new HandlerThread("HttpUploader");
thread.start();
mUploadLooper = thread.getLooper();
mUploadHandler = new ServiceHandler(mUploadLooper);
}
public void onStart(Intent uploadintent, int startId) {
// recup des data pour envoi via msg dans la msgqueue pour traitement
Message msg = mUploadHandler.obtainMessage();
msg.arg1 = startId;
//on place l'uri reçu dans l'intent dans le msg pour le handler
msg.obj = uploadintent.getData();
mUploadHandler.sendMessage(msg);
Log.d(getClass().getSimpleName(), "Sending: " + msg);
}
public void doHttpUpload(Uri myImage) {
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
String photofile = null;
String httpResponse; //to read http response
String filename=null;
String urlString = "http://www.site.com/fileUpload.php";
HttpURLConnection conn = null;
InputStream fis = null;
Bitmap mBitmap=null;
String pathfile;
if (myImage != null) {
//on récupère le nom du fichier photo construit avec date et heure
filename = "photo.jpg";
String[] projection = { MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.DISPLAY_NAME};
ContentResolver cr = getContentResolver();
Cursor c = cr.query(myImage, projection, null, null, null);
if (c!=null && c.moveToFirst()) {
pathfile = c.getString(0); //column0Value
photofile = c.getString(1); //column1Value
Log.i(getClass().getSimpleName(),"Data : " +pathfile);
Log.i(getClass().getSimpleName(),"Display name : " + photofile);
}
try {
fis = getContentResolver().openInputStream(myImage);
mBitmap = BitmapFactory.decodeStream(fis);
try {
int bytesAvailable = fis.available();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Log.i(getClass().getSimpleName(),"échec de lecture de la photo");
stopSelf();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
Toast.makeText(HttpUploader.this, "échec de lecture de la photo ", Toast.LENGTH_SHORT).show();
Log.i(getClass().getSimpleName(),"échec de lecture de la photo");
stopSelf();
}
} else Log.i(getClass().getSimpleName(),"myImage is null");
try {
URL site = new URL(urlString);
conn = (HttpURLConnection) site.openConnection();
//on peut écrire et lire
conn.setDoOutput(true);
conn.setDoInput(true);
// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
DataOutputStream dos = new DataOutputStream( conn.getOutputStream() );
dos.writeBytes(twoHyphens + boundary + lineEnd);
Log.i(getClass().getSimpleName(),"Display name : " + photofile);
Log.i(getClass().getSimpleName(),"Filename : " + filename);
dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + filename + "\"" + lineEnd);
dos.writeBytes(lineEnd);
Log.i(getClass().getSimpleName(),"Headers are written");
//compression de image pour envoi
mBitmap.compress(CompressFormat.JPEG, 75, dos);
// send multipart form data necesssary after file data...
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// close streams
fis.close();
dos.flush();
dos.close();
Log.e("fileUpload","File is written on the queue");
} catch (MalformedURLException e) {
e.printStackTrace();
Toast.makeText(HttpUploader.this, "échec de connexion au site web ", Toast.LENGTH_SHORT).show();
Log.i(getClass().getSimpleName(),"échec de connexion au site web 1");
} catch (IOException e) {
e.printStackTrace();
Toast.makeText(HttpUploader.this, "échec de connexion au site web ", Toast.LENGTH_SHORT).show();
Log.i(getClass().getSimpleName(),"échec de connexion au site web 2");
}
//lecture de la réponse http
try {
BufferedReader rd = new BufferedReader(new InputStreamReader(conn.getInputStream()));
Log.i(getClass().getSimpleName(),"try HTTP reponse");
while ((httpResponse = rd.readLine()) != null) {
Log.i(getClass().getSimpleName(),"HTTP reponse= " + httpResponse);
if(httpResponse.contains("error")) {
//there is a http error
check += 1;
}
}
rd.close();
} catch (IOException ioex){
Log.e("HttpUploader", "error: " + ioex.getMessage(), ioex);
ioex.printStackTrace();
Toast.makeText(HttpUploader.this, "échec de lecture de la réponse du site web ", Toast.LENGTH_SHORT).show();
Log.i(getClass().getSimpleName(),"échec de lecture de la réponse du site web");
}
}
// Method called when the (instance of) the Service is requested to terminate
public void onDestroy() {
mUploadLooper.quit();
if(check == 0) { //http response contains no error
Toast.makeText(HttpUploader.this, "photo envoyée", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(HttpUploader.this, "échec d'envoi de la photo", Toast.LENGTH_SHORT).show();
}
super.onDestroy();
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
Le fichier de layout main.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
<Button
android:id="@+id/send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10px"
android:text="Envoi" />
</LinearLayout>
A vous de jouer !
Une mise à jour de l’appli Ptit Coin
Une mise à jour de l’appli P’tit Coin est disponible sur Android Market.
J’ai réduis la taille des photos prises depuis l’application pour que l’envoi soit plus rapide.
Twitter Weekly Updates for 2010-01-24
- RT @Korben: "Le petit bonhomme en mousseuuuuu…" lalalalalallaa : pas merci : toute la matinée dans la tête ;o) arhhhhhhhhhhhhhhh #
- de retour de la nuit sans web…… ouf ! bien 45 min sans DNS pour nous quand même ! #
- RT @mrboo: C'est toujours bon de le rappeler : http://bit.ly/7rhoOh #
- et hop la première appli android made in chez nous nous se trouve sur le market….. : http://bit.ly/4xbtGe #
- une suggestion de bon plugin wordpress pour insérer du code source dans un post ??? #
- c'est sympa : http://bit.ly/4s6O7I et c'est Yrgane qui le fait : http://bit.ly/7gYH7f #
- @Alkanz oui sanitaire est le bon mot ! ça pousse à la réflexion ! vulgaire non, c'est le style larcenet…. in reply to Alkanz #
- RT @AymericJ: En train de relire avec un certain plaisir cette perle de Larcenet : http://bit.ly/79Ebji : troublant de vérité ! #
- RT @dauran: Aider une association bien implantée au cœur même d'Haïti http://bit.ly/5IPMrk à RT svp #
- RT @romm1: La stratégie d'Archos face à Apple : le rôle clé d'Androïd http://bit.ly/6j3UPX #
- @AymericJ : tweetDeck….. in reply to AymericJ #
- android market : 25$ à payer pour avoir le droit de publier une application ??????? #
- RT @mlerouzic: Ah !
=> La France et l'Allemagne déconseillent l'utilisation d'Internet Explorer http://bit.ly/5rLaZt : enfin !!! # - RT @kreestal: Si vous cherchez une mini machine à donuts, c'est par ici: http://bit.ly/8p91n4 -_-; : j'en veux une !!! #
Powered by Twitter Tools
Un peu de sagesse zen.
L’auteur du blog feuille de chou donne sa liste de livres zen. Je n’en ai leu aucun mais la seule citation du livre Les quatre accords toltèques, de Miguel Ruiz me plait beaucoup :
Quatre principes de vie issus de la sagesse amérindienne. Quatre phrases simples qui changent la vie, mais pas si faciles que cela à mettre en pratique:
- Que votre parole soit impeccable;
- Ne réagissez à rien de façon personnelle;
- Ne faites aucune supposition;
- Faites toujours de votre mieux.
Ces 4 principes devraient être appliqués par tous (moi la première) lors de nos digressions sur le web…..
A méditer donc … euh, non, à appliquer ;o)
L’appli P’tit Coin…
Et voilà après tout ce boulot, le plaisir de publier ! Une application android pour téléphone android !
L’appli P’tit Coin est disponible sur Android Market dans la catégorie voyage, elle est GRATUITE.
J’ai mis à jour la fiche sur Androlib.
Une description rapide : cette application permet de trouver les toilettes publiques autour de vous.
L’idée c’est que tout le monde peut ajouter des toilettes pour grossir la base de données.
Les plus :
- vous pouvez paramétrer la distance de recherche : quand on est à pied, une distance de 1 km c’est bien, en voiture, 10 ou 20 km c’est mieux,
- vous pouvez associer une photo prise avec votre téléphone avec les P’tit Coin que vous ajoutez,
- vous pouvez créer un compte sur le site web associé à l’appli : www.ptitcoin.com
- si vous avez un compte sur le site web associé, vous pouvez enregistrer votre mot de passe et votre login dans l’application pour retrouver ensuite sur internet les P’tits Coin que vous avez ajoutés.
A chaque P’tit Coin entré, il y a au moins un commentaire / nom ou adresse associé. Vous pouvez ensuite en plus mettre une note (de 1 à 4) au P’tit Coin que vous ajoutez.
Android WebView
ou comment ouvrir un navigateur web depuis une appli….
Je rédige ce petit tutoriel car l’exemple qui se trouve sur le site web d’android ne fonctionne pas. Le voici donc revu et corrigé !
L’objet WebView vous permet de créer votre propre Activity pour un browser internet.
Ca peut être l’activité principale de votre application ou elle peut être lancée via un intent.
Pour tester, créer un nouveau projet OnTheWeb avec comme activity : OnTheWeb et comme nom de package : com.test.ontheweb.
Voici le code de l’activité :
package com.test.ontheweb;
import android.app.Activity;
import android.os.Bundle;
import android.view.KeyEvent;
import android.webkit.WebView;
import android.webkit.WebViewClient;
public class OnTheWeb extends Activity {
WebView webview;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.mywebview);
webview = (WebView)findViewById(R.id.webview);
webview.setWebViewClient(new myWebViewClient());
webview.getSettings().setJavaScriptEnabled(true);
webview.loadUrl("http://www.dansunan.com");
}
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_BACK) && webview.canGoBack()) {
webview.goBack();
return true;
}
return super.onKeyDown(keyCode, event);
}
private class myWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
}
}
Et le fichier mywebview.xml qui va bien :
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical"> <WebView android:id="@+id/webview" android:layout_width="fill_parent" android:layout_height="fill_parent" /> </LinearLayout>
Bien sûr , pour avoir accès à internet, il faut ajouter à votre fichier AndroidManifest.xml la ligne :
<uses-permission android:name=”android.permission.INTERNET” />
NB : l’erreur du tutoriel original se trouve dans le fichier .xml qui décrit la WebView.
La LinearLayout définie doit avoir les propriétés :
android:layout_width=”fill_parent”
android:layout_height=”fill_parent”
au lieu de :
android:layout_width=”wrap_content”
android:layout_height=”wrap_content”
Du changement….
Comme vous ne le savez peut être pas je travaille avec ce cher Dauran dans une entreprise (la notre) du même nom.
Du coup dauran.com c’est un peu le nom de domaine de notre boulot.
Du coup www.dansunan.com reste le blog Dans un an… mais se trouve à l’adresse http://flo.dauran.com.
Du coup je vous invite à continuer à me suivre, les 2 adresses fonctionnent toujours, vive le redirect php !
Du coup je vais essayer de faire évoluer ce blog vers plus de technique….. Mon dada en ce moment c’est Android avec du développement d’application et de site web associé….
A suivre…….
Twitter Weekly Updates for 2010-01-17
- RT @ElianChrebor: Amazing Wild Life photo gallery by Nicj Brandt http://bit.ly/5WU1Yv #photo #animals #wildlife (via @mrboo) #
- RT @Vinvin:
RT @mediamaispasque: Besson a suspendu les expulsions vers Haïti, il est cool ce mec finalement ;o) # - @donkey20 : une spéciale dédicace…… http://twitpic.com/xo440 #
Powered by Twitter Tools
Twitter Weekly Updates for 2010-01-10
- @donkey20 : tu les bichonnes les petits ;o) in reply to donkey20 #
- j'adore parler toute seule quand mon voisin de bureau à son casque sur les oreilles ;o) #
- Nexus One : un concurrent de poids à l'iPhone c'est bien, un outil de monopole de plus pour google sur les pubs = pas top => avis partagé #
- hey de retour sur twitter ! peut être un peu tard : bonne année 2010 ;o) original non !? #
- RT @ThibautNinove: Voilà une des raisons pour lesquelles je ne risque pas de troquer mon iPhone contre un Nexus One http://tnv.li/aqD6X #
Powered by Twitter Tools
Twitter Weekly Updates for 2009-12-27
- Les petits lutins ont fait leur travail hier soir : emballage des cadeaux terminé….. #
Powered by Twitter Tools