Retrofit API для получения изображения PNG

Привет, я новичок в Retrofit Framework для Android. Я мог бы получить ответы JSON от REST-сервисов, используя его, но я не знаю, как загрузить png с помощью модернизации. Я пытаюсь загрузить png с этого URL: http://wwwns.akamai.com/media_resources/globe_emea.png. Каким должен быть ответный объект, который будет указан в Callback<> для достижения этой цели.

9 ответов

Решение

Как уже упоминалось, вы не должны использовать Retrofit для фактической загрузки самого изображения. Если ваша цель - просто загрузить контент, не отображая его, вы можете просто использовать Http-клиент, такой как OkHttp, который является еще одной из библиотек Square.

Вот несколько строк кода, которые позволят вам загрузить это изображение. Затем вы можете прочитать данные из InputStream.

    OkHttpClient client = new OkHttpClient();

    Request request = new Request.Builder()
            .url("http://wwwns.akamai.com/media_resources/globe_emea.png")
            .build();

    client.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Request request, IOException e) {
            System.out.println("request failed: " + e.getMessage());
        }

        @Override
        public void onResponse(Response response) throws IOException {
            response.body().byteStream(); // Read the data from the stream
        }
    });

Несмотря на то, что Retrofit не подходит для ответа на ваш вопрос, подпись вашего определения интерфейса будет такой. Но опять же не делай этого.

public interface Api {
    @GET("/media_resources/{imageName}")
    void getImage(@Path("imageName") String imageName, Callback<Response> callback);
}

Конечно, мы обычно используем Picasso для загрузки изображения, но иногда нам действительно нужно использовать Retrofit для загрузки специального изображения (например, получить изображение с картинки), вам нужно добавить заголовок для запроса, получить некоторое значение из заголовка ответа (конечно, вы можете также используйте Picasso + OkHttp, но в проекте вы уже использовали Retrofit для обработки большинства сетевых запросов), поэтому здесь рассмотрим, как реализовать Retrofit 2.0.0 (я уже реализовал в своем проекте).

Ключевым моментом является то, что вам нужно использовать okhttp3.ResponseBody чтобы получить ответ, иначе Retrofit будет анализировать данные ответа как JSON, а не двоичные данные.

коды:

public interface Api {
    // don't need add 'Content-Type' header, it's useless
    // @Headers({"Content-Type: image/png"})
    @GET
    Call<ResponseBody> fetchCaptcha(@Url String url);
}

Call<ResponseBody> call = api.fetchCaptcha(url);
call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
            if (response.isSuccessful()) {
                if (response.body() != null) {
                    // display the image data in a ImageView or save it
                    Bitmap bmp = BitmapFactory.decodeStream(response.body().byteStream());
                    imageView.setImageBitmap(bmp);
                } else {
                    // TODO
                }
            } else {
                // TODO
            }
        }

        @Override
        public void onFailure(Call<ResponseBody> call, Throwable t) {
            // TODO
        }
    });

Объявите, что он возвращает Call, например:

@GET("/api/{api}/bla/image.png")
Call<ResponseBody> retrieveImageData();

затем конвертируйте его в растровое изображение самостоятельно:

ResponseBody body = retrofitService.retrieveImageData().execute().body();
        byte[] bytes = body.bytes();
Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);

Retrofit - это библиотека REST. Вы можете использовать Retrofit только для получения URL-адреса изображения, но для отображения Image вам следует использовать Picasso: http://square.github.io/picasso/

подробности

  • Студия Android 3.1.4
  • Котлин 1.2.60
  • Дооснащение 2.4.0
  • проверено в minSdkVersion 19

Решение

объект RetrofitImage

object RetrofitImage {

    private fun provideRetrofit(): Retrofit {
        return Retrofit.Builder().baseUrl("https://google.com").build()
    }

    private interface API {
        @GET
        fun getImageData(@Url url: String): Call<ResponseBody>
    }

    private val api : API by lazy  { provideRetrofit().create(API::class.java) }

    fun getBitmapFrom(url: String, onComplete: (Bitmap?) -> Unit) {

        api.getImageData(url).enqueue(object : retrofit2.Callback<ResponseBody> {

            override fun onFailure(call: Call<ResponseBody>?, t: Throwable?) {
                onComplete(null)
            }

            override fun onResponse(call: Call<ResponseBody>?, response: Response<ResponseBody>?) {
                if (response == null || !response.isSuccessful || response.body() == null || response.errorBody() != null) {
                    onComplete(null)
                    return
                }
                val bytes = response.body()!!.bytes()
                onComplete(BitmapFactory.decodeByteArray(bytes, 0, bytes.size))
            }
        })
    }
}

Использование 1

RetrofitImage.getBitmapFrom(ANY_URL_STRING) {
   // "it" - your bitmap
   print("$it")
}

Использование 2

Расширение для ImageView

fun ImageView.setBitmapFrom(url: String) {
    val imageView = this
    RetrofitImage.getBitmapFrom(url) {
        val bitmap: Bitmap?
        bitmap = if (it != null) it else {
            // create empty bitmap
            val w = 1
            val h = 1
            val conf = Bitmap.Config.ARGB_8888
            Bitmap.createBitmap(w, h, conf)
        }

        Looper.getMainLooper().run {
            imageView.setImageBitmap(bitmap!!)
        }
    }
}

Использование расширения

imageView?.setBitmapFrom(ANY_URL_STRING)

Вы также можете использовать Retrofit для выполнения @GET и просто вернуть Response, Тогда в коде вы можете сделать isr = new BufferedInputStream(response.getBody().in()) чтобы получить входной поток изображения и записать его в растровое изображение, скажем, выполнив BitmapFactory.decodeStream(isr),

Я надеюсь, что следующий код поможет вам:

Включить следующую функцию внутри MainActivity.java:

void getRetrofitImage() {
    Retrofit retrofit = new Retrofit.Builder()
            .baseUrl(url)
            .addConverterFactory(GsonConverterFactory.create())
            .build();

    RetrofitImageAPI service = retrofit.create(RetrofitImageAPI.class);

    Call<ResponseBody> call = service.getImageDetails();

    call.enqueue(new Callback<ResponseBody>() {
        @Override
        public void onResponse(Response<ResponseBody> response, Retrofit retrofit) {

            try {

                Log.d("onResponse", "Response came from server");

                boolean FileDownloaded = DownloadImage(response.body());

                Log.d("onResponse", "Image is downloaded and saved ? " + FileDownloaded);

            } catch (Exception e) {
                Log.d("onResponse", "There is an error");
                e.printStackTrace();
            }

        }

        @Override
        public void onFailure(Throwable t) {
            Log.d("onFailure", t.toString());
        }
    });
}

Ниже приведен код обработки файла для изображения:

private boolean DownloadImage(ResponseBody body) {

        try {
            Log.d("DownloadImage", "Reading and writing file");
            InputStream in = null;
            FileOutputStream out = null;

            try {
                in = body.byteStream();
                out = new FileOutputStream(getExternalFilesDir(null) + File.separator + "AndroidTutorialPoint.jpg");
                int c;

                while ((c = in.read()) != -1) {
                    out.write(c);
                }
            }
            catch (IOException e) {
                Log.d("DownloadImage",e.toString());
                return false;
            }
            finally {
                if (in != null) {
                    in.close();
                }
                if (out != null) {
                    out.close();
                }
            }

            int width, height;
            ImageView image = (ImageView) findViewById(R.id.imageViewId);
            Bitmap bMap = BitmapFactory.decodeFile(getExternalFilesDir(null) + File.separator + "AndroidTutorialPoint.jpg");
            width = 2*bMap.getWidth();
            height = 6*bMap.getHeight();
            Bitmap bMap2 = Bitmap.createScaledBitmap(bMap, width, height, false);
            image.setImageBitmap(bMap2);

            return true;

        } catch (IOException e) {
            Log.d("DownloadImage",e.toString());
            return false;
        }
    }

Это делается с помощью Android Retrofit 2.0. Я надеюсь, что это помогло вам.

Источник: Загрузка изображений с использованием Retrofit 2.0

Простое и лучшее решение

Если ответом API является изображение, нет необходимости использовать модификацию для получения изображения. Используя GlideUrl, изображение можно легко визуализировать с помощью Glide.

             val glideUrl = GlideUrl("APICall url",LazyHeaders.Builder()
                    .addHeader("X-Api-Key", "apiKey") // if any headers are required
                    .build())
       Glide.with(requireContext()).load(glideUrl).into(imageview)

Модификация кодирует ваш байтовый массив в базу 64. Так что декодируйте вашу строку, и все готово. Таким образом, вы можете получить список изображений.

public static Bitmap getBitmapByEncodedString(String base64String) {
    String imageDataBytes = base64String.substring(base64String.indexOf(",")+1);
    InputStream stream = new ByteArrayInputStream(Base64.decode(imageDataBytes.getBytes(), Base64.DEFAULT));
    return BitmapFactory.decodeStream(stream);
}
Другие вопросы по тегам