La version courte - org.Apache...MultipartEntity
Est obsolète et sa mise à niveau, MultipartEntityBuilder
, apparaît sous-représentée dans nos forums en ligne. . Réglons ça. Comment enregistrer un rappel, afin que mon application (Android) puisse afficher une barre de progression au fur et à mesure qu'elle télécharge un fichier?
La version longue - Voici "l'exemple manquant de saleté-simple" de MultipartEntityBuilder
:
public static void postFile(String fileName) throws Exception {
// Based on: https://stackoverflow.com/questions/2017414/post-multipart-request-with-Android-sdk
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(SERVER + "uploadFile");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
builder.addPart("file", new FileBody(new File(fileName)));
builder.addTextBody("userName", userName);
builder.addTextBody("password", password);
builder.addTextBody("macAddress", macAddress);
post.setEntity(builder.build());
HttpResponse response = client.execute(post);
HttpEntity entity = response.getEntity();
// response.getStatusLine(); // CONSIDER Detect server complaints
entity.consumeContent();
client.getConnectionManager().shutdown();
} // FIXME Hook up a progress bar!
Nous devons corriger cela FIXME
. (Un avantage supplémentaire serait les téléchargements interruptibles.) Mais (corrigez-moi si je me trompe ou non), tous les exemples en ligne semblent ne pas être à la hauteur.
Celui-ci, http://Pastebin.com/M0uNZ6SB , par exemple, télécharge un fichier sous forme de "flux binaire/octet"; pas un "multipart/form-data". J'ai besoin de vrais champs.
Cet exemple, Téléchargement de fichier avec Java (avec une barre de progression) =, montre comment remplacer le *Entity
Ou le *Stream
. peut-être que je peux dire au MultipartEntityBuilder
à .create()
une entité surchargée qui enregistre la progression du téléchargement?
Donc, si je veux remplacer quelque chose et remplacer le flux intégré par un flux de comptage qui envoie un signal tous les 1000 octets, je peux peut-être étendre la partie FileBody
et remplacer son getInputStream
et/ou writeTo
.
Mais lorsque j'essaie class ProgressiveFileBody extends FileBody {...}
, Je reçois l'infâme Java.lang.NoClassDefFoundError
.
Ainsi, pendant que je fouille autour de mes fichiers .jar
, À la recherche du Def manquant, quelqu'un peut-il vérifier mes calculs et peut-être indiquer une solution plus simple que j'ai oubliée?
Le code gagnant (dans le style spectaculaire Java-Heresy (tm)) est:
public static String postFile(String fileName, String userName, String password, String macAddress) throws Exception {
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(SERVER + "uploadFile");
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
final File file = new File(fileName);
FileBody fb = new FileBody(file);
builder.addPart("file", fb);
builder.addTextBody("userName", userName);
builder.addTextBody("password", password);
builder.addTextBody("macAddress", macAddress);
final HttpEntity yourEntity = builder.build();
class ProgressiveEntity implements HttpEntity {
@Override
public void consumeContent() throws IOException {
yourEntity.consumeContent();
}
@Override
public InputStream getContent() throws IOException,
IllegalStateException {
return yourEntity.getContent();
}
@Override
public Header getContentEncoding() {
return yourEntity.getContentEncoding();
}
@Override
public long getContentLength() {
return yourEntity.getContentLength();
}
@Override
public Header getContentType() {
return yourEntity.getContentType();
}
@Override
public boolean isChunked() {
return yourEntity.isChunked();
}
@Override
public boolean isRepeatable() {
return yourEntity.isRepeatable();
}
@Override
public boolean isStreaming() {
return yourEntity.isStreaming();
} // CONSIDER put a _real_ delegator into here!
@Override
public void writeTo(OutputStream outstream) throws IOException {
class ProxyOutputStream extends FilterOutputStream {
/**
* @author Stephen Colebourne
*/
public ProxyOutputStream(OutputStream proxy) {
super(proxy);
}
public void write(int idx) throws IOException {
out.write(idx);
}
public void write(byte[] bts) throws IOException {
out.write(bts);
}
public void write(byte[] bts, int st, int end) throws IOException {
out.write(bts, st, end);
}
public void flush() throws IOException {
out.flush();
}
public void close() throws IOException {
out.close();
}
} // CONSIDER import this class (and risk more Jar File Hell)
class ProgressiveOutputStream extends ProxyOutputStream {
public ProgressiveOutputStream(OutputStream proxy) {
super(proxy);
}
public void write(byte[] bts, int st, int end) throws IOException {
// FIXME Put your progress bar stuff here!
out.write(bts, st, end);
}
}
yourEntity.writeTo(new ProgressiveOutputStream(outstream));
}
};
ProgressiveEntity myEntity = new ProgressiveEntity();
post.setEntity(myEntity);
HttpResponse response = client.execute(post);
return getContent(response);
}
public static String getContent(HttpResponse response) throws IOException {
BufferedReader rd = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
String body = "";
String content = "";
while ((body = rd.readLine()) != null)
{
content += body + "\n";
}
return content.trim();
}
# NOTE ADDED LATER: as this blasterpiece gets copied into various code lineages,
# The management reminds the peanut gallery that "Java-Heresy" crack was there
# for a reason, and (as commented) most of that stuff can be farmed out to off-
# the-shelf jar files and what-not. That's for the Java lifers to tool up. This
# pristine hack shall remain obviousized for education, and for use in a pinch.
# What are the odds??
Je ne peux pas remercier assez Phlip pour cette solution. Voici les touches finales pour l'ajout de votre support progressbar. Je l'ai exécuté dans une AsyncTask - progress ci-dessous vous permet de poster la progression dans une méthode de la AsyncTask qui appelle AsyncTask.publishProgress () pour votre classe qui s'exécute dans la AsyncTask. La barre de progression n'est pas parfaitement lisse mais au moins elle bouge. Sur un Samsung S4 téléchargeant un fichier image de 4 Mo après le préambule, il déplaçait des morceaux de 4K.
class ProgressiveOutputStream extends ProxyOutputStream {
long totalSent;
public ProgressiveOutputStream(OutputStream proxy) {
super(proxy);
totalSent = 0;
}
public void write(byte[] bts, int st, int end) throws IOException {
// FIXME Put your progress bar stuff here!
// end is the amount being sent this time
// st is always zero and end=bts.length()
totalSent += end;
progress.publish((int) ((totalSent / (float) totalSize) * 100));
out.write(bts, st, end);
}
tout d'abord: un grand merci pour la question/réponse originale. Puisque HttpPost est maintenant obsolète, je l’ai retravaillé un peu, en utilisant une entrée supplémentaire de ce article et en ai fait une micro-bibliothèque: https://github.com/licryle/HTTPPoster
Cela englobe le tout dans une tâche ASync; utilise MultipartEntityBuilder & HttpURLConnection et vous permet d'écouter les rappels.
Utiliser:
dependencies
{
compile project(':libs:HTTPPoster')
}
Vous avez besoin d'une classe pour implémenter l'interface HttpListener
afin de pouvoir écouter les rappels. Il a quatre rappels dans HTTPListener
:
Configurez la tâche ASyncTask et démarrez-la. Voici un usage rapide:
HashMap<String, String> mArgs = new HashMap<>();
mArgs.put("lat", "40.712784");
mArgs.put("lon", "-74.005941");
ArrayList<File> aFileList = getMyImageFiles();
HttpConfiguration mConf = new HttpConfiguration(
"http://example.org/HttpPostEndPoint",
mArgs,
aFileList,
this, // If this class implements HttpListener
null, // Boundary for Entities - Optional
15000 // Timeout in ms for the connection operation
10000, // Timeout in ms for the reading operation
);
new HttpPoster().execute(mConf);
espérons que cela peut aider :) N'hésitez pas à suggérer des améliorations! C'est très récent et je l'étends au fur et à mesure de mes besoins.
À votre santé