progressbar - progress circle android studio
Android: quiero mostrar el progreso de carga de archivos al usuario (7)
1) Asegúrese de realizar su carga en un Servicio con su propio hilo.
2) Para obtener el progreso: Envuelva su InputStream en esta clase y use una biblioteca httpmime.jar que tenga soporte MultiPart para HttpClient. Utilicé un hilo que verifica el progreso y actualiza la barra de progreso en la notificación.
package com.hyves.android.service.upload;
import java.io.IOException;
import java.io.InputStream;
/**
* This outputstream wraps an existing outputstream and provides
* callbacks after certain amount of bytes to a HttpCallback
*
* @author tjerk
*/
public class ProgressNotifyingInputStream extends InputStream {
private InputStream wrappedStream;
private int count = 0;
private int totalSize;
/**
* Creates a new notifying outputstream which wraps an existing one.
* When you write to this stream the callback will be notified each time when
* updateAfterNumberBytes is written.
*
* @param stream the outputstream to be wrapped
* @param totalSize the totalsize that will get written to the stream
*/
public ProgressNotifyingInputStream(InputStream stream, int totalSize) {
if(stream==null) {
throw new NullPointerException();
}
if(totalSize == 0) {
throw new IllegalArgumentException("totalSize argument cannot be zero");
}
this.wrappedStream = stream;
this.totalSize = totalSize;
}
@Override
public int read() throws IOException {
count++;
return wrappedStream.read();
}
/**
* Get progress from 0 to 100
* @return
*/
public int getProgress() {
return count * 100 / totalSize;
}
}
Subo una foto al servidor a través del HttpClient predeterminado en el SDK de Android. Quiero mostrar el progreso en la interfaz de usuario, ¿hay alguna forma de saber cuánto se ha cargado? ¿Es posible con HttpUrlConnection?
Escribí un ejemplo de cómo hacer esto exactamente -> http://toolongdidntread.com/android/android-multipart-post-with-progress-bar/
Necesitaba el progreso de carga para una imagen y no estaba usando HttpMultipartClient debido a problemas de implementación (problemas para obtener el paquete a través de los errores de gradle y dependencia). Otro problema que estaba encontrando era obtener el tamaño de archivo real de la imagen que quería cargar.
Mis requisitos también incluían tener la carga en el área de notificación. Aquí está mi solución:
Obtener el tamaño de la imagen
protected int sizeOf(Bitmap data) {
/*
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
return data.getAllocationByteCount();
} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR1) {
return data.getRowBytes() * data.getHeight();
} else {
return data.getByteCount();
}
// NONE OF THE ABOVE RETURN ACCURATE RESULTS!
// A Bitmap, when stored as a file takes up more room because it represents
// full pixel data and is not compressed on disk.
*/
byte[] bitmapdata = getBmpAsByteArray(data);
return (bitmapdata == null) ? 0 : bitmapdata.length;
}
AsyncHttpPostTask extends AsyncTask<UploadableImage, Integer, String>
AsyncHttpPostTask#onProgressUpdate
Esta función se llama desde AsyncHttpPostTask#doInBackground
que llama a la devolución de llamada para alertar la actividad del cambio de estado.
@Override
protected void onProgressUpdate(Integer... progress) {
((ImageUploadActivity) activity).updateProgress(progress[0]);
}
AsyncHttpPostTask#doInBackground
Como mencioné antes, no HttpMultipartClient
el HttpMultipartClient
, así que tuve que implementar el mío. La mayor parte de esto proviene de http://www.androidsnippets.com/multipart-http-requests
@Override
protected String doInBackground(InputStream... inStream) {
if (MainActivity.isDebugMode) {
Log.d(TAG, "doInBackground");
}
HttpURLConnection connection;
DataOutputStream outputStream;
InputStream inputStream;
String twoHyphens = "--";
String boundary = "----------MobileFormData";
String lineEnd = "/r/n";
String result;
int bytesRead, bytesAvailable, bufferSize;
byte[] buffer;
int maxBufferSize = 32768; // 2^15 = 32k -- http://.com/a/11221907/940217
try {
InputStream is = inStream[0];
totalSize = curUpImage.getFileSize();
Log.e(TAG, "Determined the file size to be " + totalSize + " bytes");
URL url = new URL(this.server);
connection = (HttpURLConnection) url.openConnection();
connection.setDoInput(true);
connection.setDoOutput(true);
connection.setUseCaches(false);
connection.setChunkedStreamingMode(maxBufferSize);
connection.setRequestMethod("POST");
connection.setRequestProperty("Connection", "Keep-Alive");
connection.setRequestProperty("User-Agent", "Android Multipart HTTP Client 1.0");
connection.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
outputStream = new DataOutputStream(connection.getOutputStream());
// Upload POST Data
Log.e(TAG, "Args: "+this.postArgs);
String[] posts = this.postArgs.split("&");
for (String post : posts) {
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
String[] kv = post.split("=");
outputStream.writeBytes(String.format("Content-Disposition: form-data; name=/"%s/"", kv[0]));
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(String.format("%s", kv[1]));
outputStream.writeBytes(lineEnd);
}
outputStream.writeBytes(twoHyphens + boundary + lineEnd);
outputStream.writeBytes("Content-Disposition: form-data; name=/"" + this.fileParamConst + "/"; filename=/"image.jpg/"" + lineEnd);
outputStream.writeBytes("Content-Type: image/jpeg" + lineEnd);
outputStream.writeBytes(lineEnd);
bytesAvailable = is.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
buffer = new byte[bufferSize];
int totalByteRead = 0;
bytesRead = is.read(buffer, 0, bufferSize);
while (bytesRead > 0) {
totalByteRead += bytesRead;
Log.w(TAG, "totalByteRead: "+totalByteRead+", totalSize: "+totalSize);
publishProgress((int) ((totalByteRead / (float) totalSize) * 100));
outputStream.write(buffer, 0, bufferSize);
bytesAvailable = is.available();
bufferSize = Math.min(bytesAvailable, maxBufferSize);
bytesRead = is.read(buffer, 0, bufferSize);
}
if (totalByteRead == 0){
Log.e(TAG, "Total bytes read from image file: "+totalByteRead);
} else {
Log.d(TAG, "Total bytes read from image file: "+totalByteRead);
}
outputStream.writeBytes(lineEnd);
outputStream.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
inputStream = connection.getInputStream();
result = this.convertStreamToString(inputStream);
is.close();
inputStream.close();
outputStream.flush();
outputStream.close();
return result;
} catch (MalformedURLException e) {
result = "Error - Malformed URL";
e.printStackTrace();
} catch (FileNotFoundException e) {
result = "Error - Image file not found.";
e.printStackTrace();
} catch (IOException e) {
result = "Error - IO Exception.";
e.printStackTrace();
}
return result;
}
AsyncHttpPostTask#onPostExecute
Aquí analizo la respuesta JSON de mi servidor para ver si la carga se pudo procesar correctamente, luego devuelvo un mensaje a la Actividad que controla la notificación.
@Override
protected void onPostExecute(String result) {
String resultString = null;
if (MainActivity.isDebugMode){
Log.d(TAG, "Async result: "+result);
}
boolean successful = false;
String[] errorMessages = null;
try {
JSONObject mainObject = new JSONObject(result);
String resultJsonString = mainObject.getString("result");
JSONArray messagesJsonArray = mainObject.getJSONArray("messages");
if (resultJsonString != null){
if (resultJsonString.equalsIgnoreCase("success")){
successful = true;
} else {
Log.e(TAG, "result was: "+resultJsonString);
}
}
errorMessages = new String[messagesJsonArray.length()];
for (int i = 0; i < messagesJsonArray.length(); i++){
errorMessages[i]= (String)messagesJsonArray.get(i);
}
} catch (JSONException e){
Log.e(TAG, "JSON Exception -- The string that I tried to parse was:/n"+result);
e.printStackTrace();
}
if (successful) {
Toast.makeText(this.activity, "Upload completed successfully!", Toast.LENGTH_SHORT).show();
resultString = "Upload complete.";
} else {
String eMessages;
if (errorMessages != null && errorMessages.length > 0){
eMessages = TextUtils.join(", ", errorMessages);
resultString = "Image upload failed:/n"+eMessages;
} else {
resultString = "Image upload failed!";
}
}
((ImageUploadActivity) activity).updateProgress(null);
((ImageUploadActivity) activity).setPostResult(resultString);
}
Mostrando el progreso
En la Actividad que es responsable de la notificación, tengo esta función de devolución de llamada que se llama desde la tarea asíncrona. Mostrar el progreso aquí también se puede hacer usando una de las soluciones discutidas en la publicación del blog de John Russell . Esta actividad se inicia con el modo singleTop
modo que cuando se lleva al frente con la notificación, se conserva el estado.
ImageUploadActivity # buildNotify
private void buildNotify(){
Intent resultIntent = new Intent(this, ImageUploadActivity.class);
// Because clicking the notification opens a new ("special") activity, there''s
// no need to create an artificial back stack.
PendingIntent resultPendingIntent =
PendingIntent.getActivity(
this,
0,
resultIntent,
PendingIntent.FLAG_UPDATE_CURRENT
);
mNotifyManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
mBuilder = new NotificationCompat.Builder(this);
mBuilder.setContentIntent(resultPendingIntent);
mBuilder.setContentTitle("Image Upload")
.setContentText("Image upload in progress")
.setSmallIcon(android.R.drawable.ic_menu_upload);
}
ImageUploadActivity # updateProgress
Este método elimina el progreso de la notificación y también de la IU contenida en la Actividad.
public void updateProgress(Integer progress){
this.currentProgress = progress;
if (uploadStatusTV != null && this.currentProgress != null){
currentStatus = "uploading image: "+this.currentProgress+"%";
uploadStatusTV.setText("uploading image: "+this.currentProgress+"%");
if (mBuilder == null){
buildNotify();
}
// Sets the progress indicator to a max value, the
// current completion percentage, and "determinate" state
mBuilder.setProgress(100, currentProgress, false);
// Displays the progress bar for the first time.
mNotifyManager.notify(notify_id, mBuilder.build());
} else if (uploadStatusTV != null){
return;
} else {
Log.e(TAG, "You should never see this message.");
finish();
}
}
No he usado httpclient pero he hecho algo como lo que deseas con AsyncTask
.
private class DownloadImageTask extends AsyncTask<String, Void,Bitmap>{
protected Bitmap doInBackground(String... urls) {
while (myProgress<length){
myProgress=myProgress+1;
myProgressBar.setProgress(myProgress);
}
return decodeImage(urls[0]);
}
protected void onPostExecute(Bitmap result) {
//dialog.dismiss();
imView.setImageBitmap(result);
}
protected void onPreExecute() {
/* Things to be done while execution of long running operation is
in progress. For example updating ProgressDialog */
dialog = ProgressDialog.show(BusinessCardActivity.this,
"Loading.........","Wait For Few Second", true);
}
}
Ver en el proceso en segundo plano Estoy incrementando la barra de progreso y decodificando la imagen y en la ejecución posterior estoy configurando la imagen.
No trabajé con esa API, pero note que HttpClient no es específico de Android:
org.apache.http.client.HttpClient
Por lo tanto, si busca "progreso de HttpClient" en Google, hay una cantidad de publicaciones que pueden ser útiles.
Además, considera que el progreso de descarga de Android post
O debería usar AsyncTask para realizar el proceso real de carga de archivos y usar ProcessDialog para iniciar y detener el proceso.
Puede ver este código, http://github.com/narup/mymobile/blob/master/pbdroid/src/com/example/android/skeletonapp/StoreListActivity.java escribí para cargar los datos JSON a través de HTTP y uso el proceso diálogo.
La parte principal del código es:
private class LoadStoresTask extends AsyncTask<String, Void, List<Store>> {
@Override
protected List<Store> doInBackground(String... params) {
return WsiStoresClient.connect(params[0]);
}
@Override
protected void onPostExecute(List<Store> result) {
dismissDialog(BUSY_DIALOG_KEY);
}
}
Para mi HTTPClient no funcionó. Los bytes se almacenaron en búfer en partes y se enviaron como totales después de la llamada de vaciado. Lo que funcionó fue enviarlo a nivel de socket.
Puede usar HttpMultipartClient para esto (enlace actualizado el 30-10-2011): http://code.google.com/p/rainbowlibs/source/browse/android/trunk/rainbowlibs/src/it/rainbowbreeze/libs/data/HttpMultipartClient.java?spec=svn94&r=94
Especifique la cantidad de bytes para cada parte y actualice la barra de progreso en el bucle while:
while ((line = reader.readLine ())! = null &&! headersEnd)
Llame al HttpMultipartClient como sigue:
HttpMultipartClient httpMultipartClient = new HttpMultipartClient("bluppr.com", "/api/order/create", 80);
FileInputStream fis = new FileInputStream(path + fileName);
httpMultipartClient.addFile(fileName, fis, fis.available());
httpMultipartClient.setRequestMethod("POST");
httpMultipartClient.send();
En el lado del servidor use:
<?php
$target_path = "uploads/";
$target_path = $target_path . basename( $_FILES[''uploadedfile''][''name'']);
if(move_uploaded_file($_FILES[''uploadedfile''][''tmp_name''], $target_path)) {
echo "The file ". basename( $_FILES[''uploadedfile''][''name''])." has been uploaded " .$_POST["order"]. " post";
} else{
echo "There was an error uploading the file, please try again!";
}
?>
Utilicé esto para Bluppr Postcards, funcionó a la perfección. Si necesita más información, hágamelo saber.