Android 改造 API 以检索 png 图像

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25462523/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 09:27:01  来源:igfitidea点击:

Retrofit API to retrieve a png image

androidretrofit

提问by Pradeep CR

Hi I am new to Retrofit framework for Android. I could get JSON responses from REST services using it but I don't know how to download a png using retrofit. I am trying to download the png from this url: http://wwwns.akamai.com/media_resources/globe_emea.png. What should be response Object to be specified in the Callback<> to achieve this.

嗨,我是 Android 的 Retrofit 框架的新手。我可以使用它从 REST 服务获得 JSON 响应,但我不知道如何使用改造下载 png。我正在尝试从此网址下载 png:http: //wwwns.akamai.com/media_resources/globe_emea.png。要在 Callback<> 中指定的响应对象应该是什么来实现这一点。

回答by Miguel Lavigne

As mentioned you shouldn't use Retrofit to actually download the image itself. If your goal is to simply download the content without displaying it then you could simply use an Http client like OkHttpwhich is another one of Square's libraries.

如前所述,您不应该使用 Retrofit 来实际下载图像本身。如果您的目标是简单地下载内容而不显示它,那么您可以简单地使用像OkHttp这样的 Http 客户端,它是 Square 的另一个库。

Here's a few lines of code which would have you download this image. You could then read the data from the InputStream.

这是几行代码,可以让您下载此图像。然后您可以从 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
        }
    });

Even though Retrofit isn't the man for the job to answer your question, the signature of your Interface definition would like this. But again don't do this.

尽管 Retrofit 不是回答您问题的人,但您的接口定义的签名会是这样。但再次不要这样做。

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

回答by Spark.Bao

Of course we usually use Picassoto load image, but sometimes we really need use Retrofitto load a special image (like fetch a captcha image), you need add some header for request, get some value from header of response (of course you can also use Picasso + OkHttp, but in a project you have already use Retrofit to handle most of net requests), so here introduce how to implement by Retrofit 2.0.0 (I have already implemented in my project).

当然我们通常使用Picasso来加载图片,但有时我们真的需要使用Retrofit来加载一个特殊的图片(比如获取验证码图片),你需要为请求添加一些头部,从响应头部中获取一些值(当然你可以也使用Picasso + OkHttp,但是在一个项目中你已经使用了Retrofit来处理大部分的网络请求),所以这里介绍一下如何通过Retrofit 2.0.0来实现(我已经在我的项目中实现了)。

The key point is that you need use okhttp3.ResponseBodyto receive response, else Retrofit will parse the response data as JSON, not binary data.

关键是你需要okhttp3.ResponseBody用来接收响应,否则 Retrofit 会将响应数据解析为 JSON,而不是二进制数据。

codes:

代码:

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

回答by Yuraj

Retrofit is a REST library, you can use Retrofit only to get image URL but for displaying Image you should use Picasso: http://square.github.io/picasso/

Retrofit 是一个 REST 库,您只能使用 Retrofit 来获取图像 URL,但要显示图像,您应该使用 Picasso:http: //square.github.io/picasso/

回答by Alécio Carvalho

Declare it returning Call for instance:

声明它返回 Call 例如:

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

then convert it to Bitmap yourself:

然后自己将其转换为位图:

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

回答by Vasily Bodnarchuk

Details

细节

  • Android studio 3.1.4
  • Kotlin 1.2.60
  • Retrofit 2.4.0
  • checked in minSdkVersion 19
  • 安卓工作室 3.1.4
  • 科特林 1.2.60
  • 改造 2.4.0
  • 签入 minSdkVersion 19

Solution

解决方案

object RetrofitImage

对象 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))
            }
        })
    }
}

Usage 1

用法 1

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

Usage 2

用法2

Extension for ImageView

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

Usage of the extension

扩展的使用

imageView?.setBitmapFrom(ANY_URL_STRING)

回答by astryk

You could also use Retrofit to perform the @GETand just return the Response. Then in code you can do isr = new BufferedInputStream(response.getBody().in())to get the input stream of the image and write it into a Bitmap, say, by doing BitmapFactory.decodeStream(isr).

您也可以使用 Retrofit 来执行@GET并返回Response. 然后在代码中,您可以isr = new BufferedInputStream(response.getBody().in())获取图像的输入流并将其写入位图,例如,通过执行BitmapFactory.decodeStream(isr).

回答by Navneet Goel

I hope following code will help you:

我希望以下代码可以帮助您:

Include following function inside MainActivity.java:

在里面包含以下函数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());
        }
    });
}

Following is the file handling code for image:

以下是图像的文件处理代码:

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

This is done using Android Retrofit 2.0. I hope it helped you.

这是使用 Android Retrofit 2.0 完成的。我希望它对你有帮助。

Source: Image Download using Retrofit 2.0

来源:使用 Retrofit 2.0 的图片下载

回答by Ghita Tomoiaga

Retrofit is encoding your byte array to base 64. So decode your string and you are good to go. In this way you can retrieve a list of images.

Retrofit 将你的字节数组编码为 base 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);
}