Preparing to Download Bytes from a URL

Your Retrofit API interface does not support downloading an image yet. Patch that hole now. Add a new function that accepts a URL string as input and returns an executable call object (retrofit2.Call) whose result will be an okhttp3.ResponseBody.

Listing 25.5  Updating FlickrApi (api/FlickrApi.kt)

interface FlickrApi {
    ...
    @GET
    fun fetchUrlBytes(@Url url: String): Call<ResponseBody>
}

This new API function looks a little different. It accepts a URL as input and uses that parameter value directly when determining where to download the data from. Using a parameterless @GET annotation combined with annotating the first parameter in fetchUrlBytes(…) with @Url causes Retrofit to override the base URL completely. Instead, Retrofit will use the URL passed to the fetchUrlBytes(…) function.

Add a function to FlickrFetchr to fetch the bytes from a given URL and decode them into a Bitmap (Listing 25.6 ).

Listing 25.6  Adding image downloading to FlickrFetchr (FlickrFetchr.kt)

class FlickrFetchr {
    ...
    @WorkerThread
    fun fetchPhoto(url: String): Bitmap? {
        val response: Response<ResponseBody> = flickrApi.fetchUrlBytes(url).execute()
        val bitmap = response.body()?.byteStream()?.use(BitmapFactory::decodeStream)
        Log.i(TAG, "Decoded bitmap=$bitmap from Response=$response")
        return bitmap
    }
}

Here, you use Call.execute(), which executes the web request synchronously. As you have learned, networking on the main thread is not allowed. The @WorkerThread annotation indicates that this function should only be called on a background thread.

However, the annotation itself does not take care of making a thread or putting the work on a background thread. That is your job. (The @WorkerThread annotation will show a Lint error if the function you call it from is annotated with @MainThread or @UiThread. However, as of this writing, Android lifecycle functions are not annotated with @MainThread or @UiThread, even though all lifecycle functions execute on the main thread.) Eventually, you will call fetchPhoto(String) from a background thread you create.

You pull a java.io.InputStream from the response body using the ResponseBody.byteStream() function. Once you have the byte stream, you pass it to BitmapFactory.decodeStream(InputStream), which will create a Bitmap from the bytes in the stream.

The response and byte stream must be closed. Since InputStream implements Closeable, the Kotlin standard library function use(…) will clean things up when BitmapFactory.decodeStream(…) returns.

Finally, you return the bitmap that BitmapFactory constructed. With that, your API interface and repository are ready to download images.

But there is still (a lot) more work to do.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.154.103