【问题标题】:A good approach to do multipart file upload in Android在 Android 中进行多部分文件上传的好方法
【发布时间】:2016-04-25 19:12:12
【问题描述】:

我正在编写一段代码来执行多部分表单数据 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 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 库,但在上传图片等大型数据文件时,它不是一个少数工具。

我想知道我应该怎么做才能使这个电话更易于管理?

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

我改用 AsyncTask 并且现在可以正常工作。我将保持这个问题开放,看看是否有人有更好的方法。

【问题讨论】:

    标签: java android multithreading request androidhttpclient


    【解决方案1】:

    HTTP 一直是 Android 的痛点。幸运的是,我们有许多很棒的库来处理所有困难的部分。

    试试Ion

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

    它还可以做其他很酷的事情,比如智能缓存、调用上下文超出范围时自动取消请求等。

    P.S:Retrofit 是另一个很棒的库,但我自己更喜欢 Ion。只是偏好问题。

    【讨论】:

      【解决方案2】:

      上述与上传.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);
              }
      }
      

      【讨论】:

        【解决方案3】:

        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 主文件(定义插件类)

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

        【讨论】:

        • 这似乎并不是对这个问题的具体答案(只是一个仅相切相关的代码转储),并且存在根本不相关的垃圾邮件链接。
        猜你喜欢
        • 2015-04-10
        • 2018-10-15
        • 2013-05-08
        • 2018-02-27
        • 2016-10-18
        • 2011-03-15
        • 2017-07-29
        • 2021-01-19
        • 1970-01-01
        相关资源
        最近更新 更多