我通过Android SDK中的默认HttpClient将照片上传到服务器。我想在用户界面中显示进度,有没有办法找出上传了多少?是否可以使用HttpUrlConnection?
答案 0 :(得分:14)
对我来说,HTTPClient无效。缓冲部分中缓冲的字节,并在刷新调用后作为总计发送。什么工作是在套接字级别发送它。
您可以使用HttpMultipartClient(2011年10月30日更新的链接): http://code.google.com/p/rainbowlibs/source/browse/android/trunk/rainbowlibs/src/it/rainbowbreeze/libs/data/HttpMultipartClient.java?spec=svn94&r=94
指定每个部件的字节数并更新while循环中的进度条:
while((line = reader.readLine())!= null&&!headersEnd)
按照以下方式调用HttpMultipartClient:
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();
在服务器端使用:
<?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!";
}
?>
我用它来制作Bluppr明信片,就像一个魅力。如果您需要更多信息,请告诉我们。
答案 1 :(得分:3)
1)请务必使用自己的主题在服务中执行上传。
2)获取进度:将InputStream包装在此类中,并使用一个对HttpClient具有MultiPart支持的httpmime.jar库。我使用了一个线程来检查进度并更新通知中的进度条。
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;
}
}
答案 2 :(得分:2)
我需要图像的上传进度,并且因为实现问题而无法使用HttpMultipartClient(通过gradle和依赖项错误获取包时出现问题)。 我遇到的另一个问题是获取我想要上传的图像的实际文件大小。
我的要求还包括在通知区域中上传。这是我的解决方案:
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
从AsyncHttpPostTask#doInBackground
内部调用此函数,该函数调用回调以警告状态更改的活动。
@Override
protected void onProgressUpdate(Integer... progress) {
((ImageUploadActivity) activity).updateProgress(progress[0]);
}
AsyncHttpPostTask#doInBackground
正如我之前提到的,我没有使用HttpMultipartClient
,所以我必须实现自己的。其中大部分来自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://stackoverflow.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
在这里,我解析服务器的JSON响应以查看上载是否能够成功处理,然后向控制通知的活动返回一条消息。
@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);
}
在负责通知的Activity中,我有一个从异步任务调用的回调函数。此处显示进度也可以使用John Russell's blog post中讨论的解决方案之一完成。此活动以模式singleTop
启动,以便在通知时将其带到前面,状态将被保留。
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);
}
此方法会清除通知的进度以及活动中包含的用户界面。
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();
}
}
答案 3 :(得分:1)
或者您应该使用AsyncTask来执行文件上载的实际过程,并使用ProcessDialog来启动和停止该过程。
你可以看到这段代码,http://github.com/narup/mymobile/blob/master/pbdroid/src/com/example/android/skeletonapp/StoreListActivity.java我写的是通过HTTP加载JSON数据,我使用进程对话框。
代码的主要部分是:
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);
}
}
答案 4 :(得分:0)
我没有使用该API,但请注意HttpClient不是特定于Android的:
org.apache.http.client.HttpClient
因此,如果你谷歌搜索“HttpClient进展”,那么有很多帖子可能会有用。
另外,请考虑发布Android Download Progress
答案 5 :(得分:0)
我没有使用过httpclient,但我已经使用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);
}
}
在后台进程中看到我正在递增进度条并解码图像,在后期执行中我正在设置图像。
答案 6 :(得分:0)
我写了一个如何做到这一点的例子 - &gt; http://toolongdidntread.com/android/android-multipart-post-with-progress-bar/