我正在处理一段代码来执行多部分表单数据POST请求,在我的情况下,这只是将图像上传到带有参数的服务器。这就是我现在所拥有的:
我有一个触发多部分请求的按钮,在按钮OnClickListener中,我有这个代码来旋转一个新线程:
new Thread(new Runnable(){
@Override
public void run() {
String photoUri = getPhotoUri();
String url = getEndPointUrl();
try {
NewPostRequest.postFile(url, photoUri, <Other Params...>);
} catch (Exception e) {
// Exception Handling
}
}).start();
而NewPostRequest.postFile
只是使用 Apache Http客户端来发出请求,基本上如下所示:
HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost(url);
MultipartEntityBuilder builder = MultipartEntityBuilder.create();
builder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
File file = new File(fileUri);
FileBody fb = new FileBody(file);
builder.addPart("file", fb);
builder.addTextBody("param", otherParam);
HttpEntity entity = builder.build();
post.setEntity(entity);
HttpResponse response = client.execute(post);
我需要每次都旋转一个新线程,因为最近的Android版本不允许程序在UI线程上发出http请求。但是,我真的反对旋转一个随机线程,让它像上面的代码一样失控。我曾尝试使用Google Volley库,但在上传像图像这样的大型数据文件时,它并不是一种极少数的工具。
我想知道我应该做些什么来使这个电话更容易管理?
=====更新=====
我切换到使用 AsyncTask ,它现在可以正常工作了。我会保持这个问题,看看是否有人有更好的方法。
答案 0 :(得分:10)
HTTP一直是Android的痛点。幸运的是,我们有许多伟大的库来处理所有困难的部分。
试用Ion。
它允许您在后台线程中轻松执行多部分请求,并在请求完成时让您在主线程上获得回调。
当调用Context超出范围等时,它还会执行其他很酷的功能,如智能缓存,自动请求取消等。
P.S:Retrofit是另一个很棒的图书馆,但我更喜欢Ion。只是一个偏好问题。
答案 1 :(得分:3)
上述问题的解决方案与将.db(任何扩展名)文件上传到服务器有关: 以下是上传文件的步骤:
1: - new AsynUpload().execute();
2: -
class AsynUpload extends AsyncTask<Void,Integer,String>
{
String result="";
ProgressDialog dialog=null;
String iFileName = CONST.USER_NAME+".db";
String lineEnd = "\r\n";
String twoHyphens = "--";
String boundary = "*****";
String Tag="fSnd";
@Override
protected void onPreExecute()
{
Log.i("AsynUpload is callinmg...", "calling");
dialog=new ProgressDialog(Upload_Database.this);
dialog.setMessage("File uploading...");
dialog.setCancelable(false);
dialog.show();
}
@Override
protected String doInBackground(Void... params) {
try
{
UTILITIES.copyDBToSDCard();
String selectedFilePath = "/data/data/com.DxS.androidSunTec.visioapp/databases/"+CONST.USER_NAME+".db";
FileInputStream fstrm = new FileInputStream(selectedFilePath);
URL connectURL = new URL(CUSTOM_URL.UPLOAD_URL+"Default.aspx");
HttpURLConnection conn = (HttpURLConnection)connectURL.openConnection();
// Allow Inputs
conn.setDoInput(true);
// Allow Outputs
conn.setDoOutput(true);
// Don't use a cached copy.
conn.setUseCaches(false);
// Use a post method.
conn.setRequestMethod("POST");
conn.setRequestProperty("Connection", "Keep-Alive");
conn.setRequestProperty("Content-Type", "multipart/form-data;boundary="+boundary);
conn.setRequestProperty("FILE_NAME", ""+CONST.USER_NAME+".db");
DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"title\""+ lineEnd);
dos.writeBytes(lineEnd);
dos.writeBytes(""+CONST.USER_NAME);
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"description\""+ lineEnd);
dos.writeBytes(lineEnd);
dos.writeBytes(loc_code+"~"+user_code+"~"+fyid);
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + lineEnd);
dos.writeBytes("Content-Disposition: form-data; name=\"uploadedfile\";filename=\"" + iFileName +"\"" + lineEnd);
dos.writeBytes(lineEnd);
// create a buffer of maximum size
int bytesAvailable = fstrm.available();
int maxBufferSize = 1024;
int bufferSize = Math.min(bytesAvailable, maxBufferSize);
byte[ ] buffer = new byte[bufferSize];
// read file and write it into form...
int bytesRead = fstrm.read(buffer, 0, bufferSize);
while (bytesRead > 0)
{
dos.write(buffer, 0, bufferSize);
bytesAvailable = fstrm.available();
bufferSize = Math.min(bytesAvailable,maxBufferSize);
bytesRead = fstrm.read(buffer, 0,bufferSize);
}
dos.writeBytes(lineEnd);
dos.writeBytes(twoHyphens + boundary + twoHyphens + lineEnd);
// close streams
fstrm.close();
// 103424
dos.flush();
InputStream is = conn.getInputStream();
// retrieve the response from server
int ch;
StringBuffer b =new StringBuffer();
while( ( ch = is.read() ) != -1 ){ b.append( (char)ch ); }
String s=b.toString();
Log.i("Response",s);
dos.close();
result="OK";
}
catch (MalformedURLException ex)
{
result = "MalformedURLException";
Log.i(Tag, "URL error: " + ex.getMessage(), ex);
}
catch (IOException ioe)
{
result = "IOException";
Log.i(Tag, "IO error: " + ioe.getMessage(), ioe);
}
catch(Exception e)
{
Log.e("Exception","Exception"+e.getMessage());
result="FAILURE";
}
finally
{
if (result.equalsIgnoreCase("OK"))
{
File file = new File("/data/data/com.test.app/databases/"+CONST.USER_NAME+".db");
if(file.exists())
{
file.delete();
Log.i("uploading database file Deleted from sd card :", "deleted");
}
file = new File("/data/data/com.test.app/databases/"+DatabaseHelper.DB_NAME);
if(file.exists())
{
file.delete();
Log.i("Original database file Deleted from sd card :", "deleted");
}
MyActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
LayoutInflater inflater = getLayoutInflater();
View vw = inflater.inflate(R.layout.custom_title, null);
builder.setCustomTitle(vw);
builder.setMessage("File uploaded successfully!")
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
finish();
}
});
builder.create();
builder.show();
}
});
}
else
{
MyActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(MyActivity.this);
LayoutInflater inflater = getLayoutInflater();
View vw = inflater.inflate(R.layout.custom_title, null);
builder.setCustomTitle(vw);
builder.setMessage("File uploading failed, please try again!")
.setCancelable(false)
.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.cancel();
}
});
builder.create();
builder.show();
}
});
}
}
return result;
}
@Override
protected void onProgressUpdate(Integer... values)
{
super.onProgressUpdate(values);
// dialog.incrementProgressBy(5);
}
@Override
protected void onPostExecute(String result)
{
dialog.dismiss();
if (result.equalsIgnoreCase("OK"))
{
}
else
{
}
}
}
3。)UTILITIES类:
public static void copyDBToSDCard() {
try {
InputStream myInput = new FileInputStream("/data/data/com.DxS.androidSunTec.visioapp/databases/"+DatabaseHelper.DB_NAME);
Log.i("sd card path: ", ""+Environment.getExternalStorageDirectory().getPath().toString());
// File file = new File(Environment.getExternalStorageDirectory().getPath()+"/"+CONST.USER_NAME+".db");
File file = new File("/data/data/com.DxS.androidSunTec.visioapp/databases/"+CONST.USER_NAME+".db");
if (!file.exists()){
try {
file.createNewFile();
} catch (IOException e) {
Log.i("FO","File creation failed for " + file);
}
}
// OutputStream myOutput = new FileOutputStream(Environment.getExternalStorageDirectory().getPath()+"/"+CONST.USER_NAME+".db");
OutputStream myOutput = new FileOutputStream("/data/data/com.DxS.androidSunTec.visioapp/databases/"+CONST.USER_NAME+".db");
byte[] buffer = new byte[1024];
int length;
while ((length = myInput.read(buffer))>0){
myOutput.write(buffer, 0, length);
}
//Close the streams
myOutput.flush();
myOutput.close();
myInput.close();
Log.i("FO","copied");
} catch (Exception e) {
Log.i("FO","exception="+e);
}
}
答案 2 :(得分:-2)
1)创建原生Android插件,用于上传多个文件和JSON对象。 2)概念是Multipart文件上传。 3)创建离线模式同步。 4)Phonegap和Android Native Code。
Javascript调用原生Andorid代码
alert(window.FilesUpload.sendFiles(JSON.stringify(jsonObj)));
以下是Android插件(FilesUpload.java)
package com.yourpackagename.core;
import java.io.*;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.impl.client.BasicResponseHandler;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.json.JSONArray;
import org.json.JSONObject;
public class FilesUpload
{
public FilesUpload() {
}
public String sendFiles(String s) {
String responseBody = "";
try
{
JSONObject jsonObject = new JSONObject(s);
int len_outer = jsonObject.getJSONArray("electricityExpenseManagement").getJSONObject(0).length();
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("http://yourservername.com/php_file_upload/file_upload2.php");
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
StringBody elecExpObj = new StringBody(s);
reqEntity.addPart("elecExpObj", elecExpObj);
for(int i=0;i<len_outer;i++)
{
int bill_count = jsonObject.getJSONArray("electricityExpenseManagement").getJSONObject(i).getJSONArray("electricityExpenseBillInfoData").length();
for(int j=0;j<bill_count;j++)
{
String sourceFileUri = jsonObject.getJSONArray("electricityExpenseManagement").getJSONObject(0).getJSONArray("electricityExpenseBillInfoData").getJSONObject(j).getString("image_path");
String partName = jsonObject.getJSONArray("electricityExpenseManagement").getJSONObject(i).getJSONArray("electricityExpenseBillInfoData").getJSONObject(j).getString("image_base64_encode");
FileBody bin = new FileBody(new File(sourceFileUri));
reqEntity.addPart(partName, bin);
}
}
httppost.setEntity(reqEntity);
System.out.println("Requesting : " + httppost.getRequestLine());
ResponseHandler<String> responseHandler = new BasicResponseHandler();
responseBody = httpclient.execute(httppost, responseHandler);
System.out.println("responseBody : " + responseBody);
return responseBody;
}
catch (UnsupportedEncodingException e) {
e.printStackTrace();
return e.getMessage();
}
catch (ClientProtocolException e) {
e.printStackTrace();
return e.getMessage();
}
catch (IOException e) {
e.printStackTrace();
return e.getMessage();
}
catch(Exception e){
e.printStackTrace();
System.out.println("error");
return e.getMessage();
}
}
}
主要Android Java文件(定义插件类)
package com.yourpackagename.core;
import android.os.Bundle;
import org.apache.cordova.*;
public class Waterhealth extends DroidGap
{
private FilesUpload f;
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Set by <content src="index.html" /> in config.xml
super.init();
f = new FilesUpload();
appView.addJavascriptInterface(f, "FilesUpload");
super.loadUrl(Config.getStartUrl());
super.loadUrl("file:///android_asset/elect_exp_FS/index.html");
}
}
用于上传文件的PHP脚本(Webservice)
<?php
if(isset($_REQUEST['elecExpObj']))
{
$obj= json_decode(stripslashes($_REQUEST['elecExpObj']));
$len = count($obj->electricityExpenseManagement);
$str = "";
for($i=0;$i<$len;$i++)
{
$bill_count = count($obj->electricityExpenseManagement[$i]->electricityExpenseBillInfoData);
for($j=0;$j<$bill_count;$j++)
{
$filePath = $obj->electricityExpenseManagement[$i]->electricityExpenseBillInfoData[$j]->image_base64_encode;
if($_FILES[$filePath]['name'])
{
if(!$_FILES[$filePath]['error'])
{
$new_file_name = $filePath . rand() . ".jpg"; //rename file
move_uploaded_file($_FILES[$filePath]['tmp_name'], 'uploads/'.$new_file_name);
$str .= 'Congratulations! Your file was accepted.';
}
}
}
}
echo $str;
}
else{
echo "fail";
}
?>