【问题标题】:Upload an image using Google Volley使用 Google Volley 上传图片
【发布时间】:2015-06-08 10:47:43
【问题描述】:

我需要将我正在开发的应用程序中的图像上传到服务器,我想知道如何开发 Multipart Request 以使用 Google Volley 加载图像。

谢谢

【问题讨论】:

    标签: android android-volley


    【解决方案1】:

    我有一个通过Google Volley 上传图片的示例。看看:

    package net.colaborativa.exampleapp.api;
    
    import java.io.ByteArrayOutputStream;
    import java.io.File;
    import java.io.IOException;
    import java.nio.charset.Charset;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Map;
    
    import org.apache.http.entity.ContentType;
    import org.apache.http.entity.mime.HttpMultipartMode;
    import org.apache.http.entity.mime.MultipartEntityBuilder;
    
    import com.android.volley.AuthFailureError;
    import com.android.volley.NetworkResponse;
    import com.android.volley.Request;
    import com.android.volley.Response;
    import com.android.volley.Response.ErrorListener;
    import com.android.volley.Response.Listener;
    import com.android.volley.VolleyLog;
    import com.android.volley.toolbox.HttpHeaderParser;
    
    public class PhotoMultipartRequest<T> extends Request<T> {
    
    
    private static final String FILE_PART_NAME = "file";
    
    private MultipartEntityBuilder mBuilder = MultipartEntityBuilder.create();
    private final Response.Listener<T> mListener;
    private final File mImageFile;
    protected Map<String, String> headers;
    
    public PhotoMultipartRequest(String url, ErrorListener errorListener, Listener<T> listener, File imageFile){
        super(Method.POST, url, errorListener);
    
        mListener = listener;
        mImageFile = imageFile;
    
        buildMultipartEntity();
    }
    
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        Map<String, String> headers = super.getHeaders();
    
        if (headers == null
                || headers.equals(Collections.emptyMap())) {
            headers = new HashMap<String, String>();
        }
    
        headers.put("Accept", "application/json");
    
        return headers;
    }
    
    private void buildMultipartEntity(){
        mBuilder.addBinaryBody(FILE_PART_NAME, mImageFile, ContentType.create("image/jpeg"), mImageFile.getName());
        mBuilder.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
        mBuilder.setLaxMode().setBoundary("xx").setCharset(Charset.forName("UTF-8"));
    }
    
    @Override
    public String getBodyContentType(){
        String contentTypeHeader = mBuilder.build().getContentType().getValue();
        return contentTypeHeader;
    }
    
    @Override
    public byte[] getBody() throws AuthFailureError{
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        try {
            mBuilder.build().writeTo(bos);
        } catch (IOException e) {
            VolleyLog.e("IOException writing to ByteArrayOutputStream bos, building the multipart request.");
        }
    
        return bos.toByteArray();
    }
    
    @Override
    protected Response<T> parseNetworkResponse(NetworkResponse response) {
        T result = null;
        return Response.success(result, HttpHeaderParser.parseCacheHeaders(response));
    }
    
    @Override
    protected void deliverResponse(T response) {
        mListener.onResponse(response);
    }
    }
    

    你可以这样使用它:

    RequestQueue mQueue = Volley.newRequestQueue(context);
    PhotoMultipartRequest imageUploadReq = new PhotoMultipartRequest(url, ErrorListener, Listener, imageFile);
    mQueue.add(imageUploadReq);
    

    我希望这些代码能激发你的灵感。

    【讨论】:

    • 感谢您的回答。我在我的应用程序中导入了您的代码,但以下库出现错误:import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; 我应该导入哪些库?谢谢
    • Apache官网,然后下载httpclient_x.x.x.zip,然后解压这个zip文件得到httpclient_x.xxjar,然后添加到你项目的libs中。
    • 我导入了你告诉我的库,但是当它运行时,Multipart 启动了以下异常:java.lang.NoSuchFieldError: org.apache.http.message.BasicHeaderValueFormatter.INSTANCE
    • 好吧,httpmime 已被弃用,我们不再使用它..!!!可以在不使用 httpmime 库的情况下更新解决方案
    • mBuilder.build().getContentType().getValue();和 mBuilder.build().writeTo(bos);不能解决?!显式 .getContetnType() 和 .writeTo() 部分。
    【解决方案2】:

    @silverknight 的答案有效,但是,我还必须在 build.gradle 中添加以下内容以解决 httpcomponents 依赖项:

    android {
    
        ...
    
        // have to exclude these otherwise you'll get:
        // Error:Gradle: Execution failed for task: ... com.android.builder.packaging.DuplicateFileException: ...
        packagingOptions {
            exclude 'META-INF/NOTICE'
            exclude 'META-INF/LICENSE'
            exclude 'META-INF/DEPENDENCIES'
        }
    }    
    
    dependencies {
    
        ...
    
        compile 'com.android.volley:volley:1.0.0'
        compile('org.apache.httpcomponents:httpmime:4.3.6') {
            exclude module: 'httpclient'
        }
        compile 'org.apache.httpcomponents:httpclient-android:4.3.5.1'
    }
    

    注意:不要使用 org.apache.httpcomponents:httpclient

    你应该避免使用'org.apache.httpcomponents:httpclient:4.5.2' 的标准版本

    如果你尝试:

    android {
    
        ...
    
    }
    
    dependencies {
    
        ...
    
        compile 'com.android.volley:volley:1.0.0'
        compile 'org.apache.httpcomponents:httpcore:4.4.4'
        compile 'org.apache.httpcomponents:httpmime:4.5.2'
        compile('org.apache.httpcomponents:httpclient:4.5.2'
    }
    

    你会得到:

    java.lang.NoSuchFieldError: No static field INSTANCE of type Lorg/apache/http/message/BasicHeaderValueFormatter; in class Lorg/apache/http/message/BasicHeaderValueFormatter; or its superclasses (declaration of 'org.apache.http.message.BasicHeaderValueFormatter' appears in /system/framework/ext.jar)
    

    或类似于现有 cmets [1] [2] [3]

    你应该使用httpclient的Android端口,就像this SO answer一样

    注意:使用 org.apache.httpcomponents:httpmime:4.3.6

    使用org.apache.httpcomponents:httpmime:4.3.6,你不能升级到4.3.x以上的版本。例如,您可能想使用最新版本的httpmime,在撰写本文时它是4.5.2

    android {
    
        ...
    
    }
    
    dependencies {
    
        ...
    
        compile('org.apache.httpcomponents:httpmime:4.5.2') {
            exclude module: 'httpclient'
        }
        compile 'org.apache.httpcomponents:httpclient-android:4.3.5.1'
    

    使用此配置,您将在调用PhotoMultipartRequest 时获得以下信息:

    java.lang.NoSuchMethodError: No static method create(Ljava/lang/String;[Lorg/apache/http/NameValuePair;)Lorg/apache/http/entity/ContentType; in class Lorg/apache/http/entity/ContentType; or its super classes (declaration of 'org.apache.http.entity.ContentType' appears in /xxx/base.apk)
    

    【讨论】:

      【解决方案3】:

      我从https://gist.github.com/ishitcno1/11394069复制了这门课 我会告诉你如何使用它。它在我的情况下有效。复制这个类。进行必要的更改。

      package com.tagero.watchfriend;
      
      import java.io.ByteArrayOutputStream;
      import java.io.File;
      
      import java.io.IOException;
      
      import org.apache.http.HttpEntity;
      import org.apache.http.entity.mime.MultipartEntityBuilder;
      import org.apache.http.entity.mime.content.FileBody;
      
      import android.util.Log;
      
      import com.android.volley.AuthFailureError;
      import com.android.volley.NetworkResponse;
      import com.android.volley.Request;
      import com.android.volley.Response;
      import com.android.volley.VolleyLog;
      
      public class PhotoMultipartRequest extends Request<String> {
      static final String TAG = "xxxxxx";
      
      public static final String KEY_PICTURE = "kullanici_resmi";
      public static final String KEY_PICTURE_NAME = "kullanici_resmi_dosya_adi";
      
      private HttpEntity mHttpEntity;
      
      @SuppressWarnings("rawtypes")
      private Response.Listener mListener;
      
      public PhotoMultipartRequest(String url, String filePath,
              Response.Listener<String> listener,
              Response.ErrorListener errorListener) {
          super(Method.POST, url, errorListener);
      
          mListener = listener;
          mHttpEntity = buildMultipartEntity(filePath);
      }
      
      public PhotoMultipartRequest(String url, File file,
              Response.Listener<String> listener,
              Response.ErrorListener errorListener) {
          super(Method.POST, url, errorListener);
      
          mListener = listener;
          mHttpEntity = buildMultipartEntity(file);
      }
      
      private HttpEntity buildMultipartEntity(String filePath) {
          File file = new File(filePath);
          return buildMultipartEntity(file);
      }
      
      private HttpEntity buildMultipartEntity(File file) {
          MultipartEntityBuilder builder = MultipartEntityBuilder.create();
          String fileName = file.getName();
          logYazdir("fileName : " + fileName);
          FileBody fileBody = new FileBody(file);
          builder.addPart(KEY_PICTURE, fileBody);
          builder.addTextBody(KEY_PICTURE_NAME, fileName);
          return builder.build();
      }
      
      @Override
      public String getBodyContentType() {
          return mHttpEntity.getContentType().getValue();
      }
      
      @Override
      public byte[] getBody() throws AuthFailureError {
          ByteArrayOutputStream bos = new ByteArrayOutputStream();
          try {
              mHttpEntity.writeTo(bos);
          } catch (IOException e) {
              VolleyLog.e("IOException writing to ByteArrayOutputStream");
          }
          return bos.toByteArray();
      }
      
      @Override
      protected Response<String> parseNetworkResponse(NetworkResponse response) {
          return Response.success("Uploaded", getCacheEntry());
      }
      
      @SuppressWarnings("unchecked")
      @Override
      protected void deliverResponse(String response) {
          mListener.onResponse(response);
      }
      
      private void logYazdir(String str) {
          if (Sabitler.LOG_KONTROL) {
              Log.d(TAG, str);
          }
      }
      }
      

      这是上传图片的方法。

          public void resimYukle(final String filePath) {
          logYazdir("KaydolActivity-uploadImage çağırıldı!");
          logYazdir("\nfilePath : " + filePath);
          RequestQueue rq = Volley.newRequestQueue(this);
          PhotoMultipartRequest stringRequest = new PhotoMultipartRequest(
                  Sabitler.URL_RESIM_YUKLE, filePath,
                  new Response.Listener<String>() {
                      @Override
                      public void onResponse(String response) {
                          logYazdir("response : " + response);
                          JSONObject veri_json;
                          try {
                              veri_json = new JSONObject(response);
      
                              int success = 0;
                              String message = "";
                              try {
                                  success = veri_json
                                          .getInt(Sabitler.SERVER_RESP_SUCCESS);
                                  message = veri_json
                                          .getString(Sabitler.SERVER_RESP_MESSAGE);
                                  Log.d(TAG, "success : " + success
                                          + "\nmessage : " + message);
                              } catch (JSONException e) {
                                  e.printStackTrace();
                              }
                          } catch (JSONException e) {
                              e.printStackTrace();
                          }
                      }
      
                  }, new Response.ErrorListener() {
                      @Override
                      public void onErrorResponse(VolleyError error) {
                          logYazdir("Error [" + error + "]");
                          Toast.makeText(getBaseContext(),
                                  "Sunucuya bağlanılamadı!", Toast.LENGTH_LONG)
                                  .show();
                      }
                  }) {
              @Override
              protected Map<String, String> getParams() {
                  Map<String, String> params = new HashMap<String, String>();
      
                  params.put("kullanici_resmi_dosya_adi", "");
      
                  return params;
      
              }
      
          };
      
          rq.add(stringRequest);
      }
      

      你将如何获得 filePath

      @Override
          protected void onActivityResult(int requestCode, int resultCode, Intent      
                                              data) {
              logYazdir("KaydolActivity-onActivityResult çağırıldı!");
              if (requestCode == GALERIDEN_RESIM && resultCode == RESULT_OK
                      && data != null) {
                  logYazdir("KaydolActivity-GALERIDEN_RESIM çağırıldı!");
                  Uri selectedImage = data.getData();
                  String[] filePathColumn = { MediaStore.Images.Media.DATA };
      
                  Cursor cursor = getContentResolver().query(selectedImage,
                          filePathColumn, null, null, null);
                  cursor.moveToFirst();
      
                  int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                  String picturePath = cursor.getString(columnIndex);
                  cursor.close();
      
                  Bitmap bmp = null;
                  try {
                      bmp = getBitmapFromUri(selectedImage);
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
                  kullanici_resmi_iview.setImageBitmap(bmp);
      
                  resimYukle(picturePath);
      
              }
              super.onActivityResult(requestCode, resultCode, data);
      
          }
      

      最后在你的活动中定义这个,

      private int GALERIDEN_RESIM = 2;
      

      重要的部分,这是您服务器的 PHP 代码,

      <?php
      $target_dir = "resimler/";
      $target_file = $target_dir . basename($_FILES["kullanici_resmi"]["name"]);
      $uploadOk = 1;
      $imageFileType = pathinfo($target_file,PATHINFO_EXTENSION);
      // Check if image file is a actual image or fake image
      if(isset($_POST["kullanici_resmi_dosya_adi"])) {
          $check = getimagesize($_FILES["kullanici_resmi"]["tmp_name"]);
          if($check !== false) {
      
              $response["success"] = 1;
              $response["message"] = "File is an image - " . $check["mime"] . ".";
              echo json_encode($response);
      
              $uploadOk = 1;
          } else {
              $response["success"] = 0;
              $response["message"] = "File is not an image.";
              echo json_encode($response);
      
              $uploadOk = 0;
          }
      }
      // Check if file already exists
      if (file_exists($target_file)) {
          $response["success"] = 0;
          $response["message"] = "Sorry, file already exists.";
          echo json_encode($response);
      
          $uploadOk = 0;
      }
      // Check file size
      if ($_FILES["kullanici_resmi"]["size"] > 750000) {
          $response["success"] = 0;
          $response["message"] =  "Sorry, your file is too large.";
          echo json_encode($response);
      
          $uploadOk = 0;
      }
      // Allow certain file formats
      if($imageFileType != "jpg" && $imageFileType != "png" && $imageFileType != "jpeg"
      && $imageFileType != "gif" ) {
          $response["success"] = 0;
          $response["message"] =  "Sorry, only JPG, JPEG, PNG & GIF files are allowed.";
          echo json_encode($response);
      
          $uploadOk = 0;
      }
      // Check if $uploadOk is set to 0 by an error
      if ($uploadOk == 0) {
          $response["success"] = 0;
          $response["message"] =  "Sorry, your file was not uploaded.";
          echo json_encode($response);
      // if everything is ok, try to upload file
      } else {
          if (move_uploaded_file($_FILES["kullanici_resmi"]["tmp_name"], $target_file)) {
              $response["success"] = 0;
              $response["message"] =  "The file ". basename( $_FILES["kullanici_resmi"]["name"]). " has been uploaded.";
              echo json_encode($response);
          } else {
              $response["success"] = 0;
              $response["message"] =  "Sorry, there was an error uploading your file.";
              echo json_encode($response);
          }
      }
      ?>
      

      您应该确保以这种方式发送您的文件,

      private HttpEntity buildMultipartEntity(File file) {
          MultipartEntityBuilder builder = MultipartEntityBuilder.create();
          String fileName = file.getName();
          logYazdir("fileName : " + fileName);
          FileBody fileBody = new FileBody(file);
          builder.addPart(KEY_PICTURE, fileBody);
          builder.addTextBody(KEY_PICTURE_NAME, fileName);
          return builder.build();
      }
      

      并注意这一点,

      public static final String KEY_PICTURE = "kullanici_resmi";
      

      kullanici_resmi

      在 PHP 代码中用于表示图像文件。 我猜这样,你可以发送任何文件。 对不起,我的解释很糟糕,我试图解释一切。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-10-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-19
        相关资源
        最近更新 更多