Загрузить изображение с помощью Google Volley

Мне нужно было бы загрузить изображение из приложения, которое я разрабатываю, на сервер, и я хотел бы знать, как я могу разработать составной запрос для загрузки изображения с помощью Google Volley.

Спасибо


person BigNick    schedule 03.04.2015    source источник


Ответы (3)


У меня есть пример загрузки изображений 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);

Я надеюсь, что эти коды вдохновят вас.

person SilentKnight    schedule 03.04.2015
comment
Спасибо за ответ. Я импортировал ваш код в свое приложение, но получаю сообщение об ошибке для следующих библиотек: import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.HttpMultipartMode; import org.apache.http.entity.mime.MultipartEntityBuilder; Какие библиотеки мне следует импортировать? Спасибо - person BigNick; 03.04.2015
comment
зайдите на официальный сайт Apache, а затем загрузите httpclient_x.x.x.zip, а затем распакуйте этот zip-файл, чтобы получить httpclient_x.x.x.jar, затем добавьте его в libs вашего проекта. - person SilentKnight; 03.04.2015
comment
Я импортировал библиотеку, которую вы мне сказали, но при ее запуске Multipart запускается следующее исключение: java.lang.NoSuchFieldError: org.apache.http.message.BasicHeaderValueFormatter.INSTANCE - person BigNick; 03.04.2015
comment
Не могли бы вы предоставить пример своего кода, как вы использовали этот класс PhotoMultipartRequest для загрузки изображения. Спасибо - person Thiago; 17.07.2015
comment
я должен опубликовать изображение с именем параметра ?imageFile =, где я должен указать это - person Prasanna Anbazhagan; 03.09.2015
comment
Откуда вы скопировали и вставили этот код?? Я получил эту ошибку: java.lang.NoSuchFieldError: нет статического поля INSTANCE типа Lorg/apache/http/message/BasicHeaderValueFormatter; в классе Lorg/apache/http/message/BasicHeaderValueFormatter; или его суперклассы (объявление «org.apache.http.message.BasicHeaderValueFormatter» появляется в /system/framework/ext.jar) - person Jimit Patel; 26.09.2015
comment
Попробуйте другую версию httpclient.jar. API немного различается в зависимости от версии. - person SilentKnight; 28.09.2015
comment
хорошо, httpmime устарел, и мы больше не используем его..!!! может обновить решение без использования библиотеки httpmime - person mudit_sen; 04.12.2015
comment
Этот код дает мне нулевой ответ в моем Response.Listener. Кто-нибудь смог это исправить? - person QuinnFreedman; 03.08.2016
comment
mBuilder.build().getContentType().getValue(); и mBuilder.build().writeTo(bos); нельзя решить?! Явно укажите части .getContetnType() и .writeTo(). - person Suisse; 28.08.2016

Ответ @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)

или что-то похожее на существующие комментарии [1] [2] [3].

Вам лучше использовать порт Android httpclient в соответствии с этим ответом SO

ПРИМЕЧАНИЕ. Используйте 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)
person Donovan Muller    schedule 29.03.2016

Я скопировал этот класс из 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 для обозначения файла изображения. Я думаю, таким образом, вы можете отправить любой файл. Извините за мои плохие объяснения, я пытался объяснить все.

person resw67    schedule 10.04.2016