2013-12-13 53 views
1

我正在處理一段代碼以執行多部分表單數據POST請求,在我的情況下,這只是將圖像上載到具有參數的服務器。這是我現在有:在Android中執行多部分文件上傳的好方法

我有一個按鈕來觸發多的要求,在按鈕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只是使用阿帕奇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庫,但在上傳大型數據文件(如圖像)時,它並不是一個小工具。

我在想我應該怎麼做才能使這個調用更易於管理?

===== UPDATE =====

我切換到使用的AsyncTask和現在它的工作原理確定。我會繼續討論這個問題,看看有沒有更好的方法。

回答

10

HTTP一直是Android的痛點。幸運的是,我們有許多偉大的圖書館來照顧所有困難的部分。

試用Ion

它允許您輕鬆地在後臺線程中執行多部分請求,並讓您在請求完成時在主線程上獲得回調。

它也確實像智能緩存,自動請求取消等涼的東西,當調用上下文超出範圍等

P.S:Retrofit是另一個偉大的圖書館,但我更喜歡自己的離子。只是一個偏好問題。

+2

+1我介紹給離子。 –

-2

1)創建本機Android插件,用於上傳多個文件以及JSON對象。 2)概念是多部分文件上傳。 3)創建離線模式同步。 4)Phonegap和Android本機代碼。

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文件上傳文件(web服務)

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

這似乎並不真正是對這個問題的具體回答(只是代碼轉儲只與切線相關),並且垃圾鏈接根本不相關。 – laalto

3

該解決方案針對上述(定義插件類)

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腳本與將.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)公用事業類:

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