在Android中进行多部分文件上传的好方法

我正在处理一段代码来执行多部分表单数据POST请求,在我的情况下,这只是将图像上传到带有参数的服务器。 这就是我现在拥有的:

我有一个触发多部分请求的按钮,在按钮OnClickListener中,我有这个代码来旋转一个新线程:

new Thread(new Runnable(){ @Override public void run() { String photoUri = getPhotoUri(); String url = getEndPointUrl(); try { NewPostRequest.postFile(url, photoUri, ); } catch (Exception e) { // Exception Handling } }).start(); 

NewPostRequest.postFile只是使用Apache Http Client发出请求,基本如下:

 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库,但在上传像image这样的大型数据文件时,它并不是少数工具。

我想知道我应该做些什么来使这个电话更容易管理?

=====更新=====

我切换到使用AsyncTask ,它现在可以正常工作。 我将保持这个问题,看看是否有任何人有更好的方法。

HTTP一直是Android的痛点。 幸运的是,我们有许多伟大的图书馆来处理所有困难的部分。

尝试离子 。

它允许您在后台线程中轻松执行多部分请求,并在请求完成时让您在主线程上获得回调。

当调用Context超出范围等时,它还会执行其他很酷的function,如智能缓存,自动请求取消等。

PS: Retrofit是另一个很棒的图书馆,但我更喜欢Ion。 只是一个偏好的问题。

上述问题的解决方案与将.db(任何扩展名)文件上传到服务器有关:以下是上传文件的步骤:

1: – new AsynUpload().execute();

2: –

 class AsynUpload extends AsyncTask { 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); } } 

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 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  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)

 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"; } ?>