27
Search

Your next task with PhotoGallery is to search photos on Flickr. You will learn how to integrate search into your app using SearchView. SearchView is an action view class – a view that can be embedded right into your Toolbar.

The user will be able to press on the SearchView, type in a query, and submit it. Submitting the query will send the query string to Flickr’s search API and populate the RecyclerView with the search results (Figure 27.1). The query string itself will be persisted to the filesystem. This means the user’s last query will be accessible across restarts of the app and even the device.

Figure 27.1  App preview

Screenshot shows the preview of outer space app. The screen shows thumbnails of images on top and keyboard below.

Searching Flickr

Let’s begin with the Flickr side of things. To search Flickr, you call the flickr.photos.search method. Here is what a GET request to search for the text cat looks like:

https://api.flickr.com/services/rest/?method=flickr.photos.search
&api_key=xxx&format=json&nojsoncallback=1&text=cat

The method is set to flickr.photos.search. A new parameter, text, is added and set to whatever string you are searching for (cat, in this case).

While the search request URL differs from the one you used to request recent photos, the format of the JSON returned remains the same. This is good news, because it means you can use the same JSON parsing code you already wrote, regardless of whether you are searching or getting recent photos.

First, refactor some of your old FlickrFetchr code to reuse the parsing code across both scenarios. Start by adding constants for the reusable pieces of the URL, as shown in Listing 27.1. Cut the URI-building code from fetchItems and paste it as the value for ENDPOINT. However, make sure to only include the shaded parts. The constant ENDPOINT should not contain the method query parameter, and the build statement should not be converted to a string using toString().

Listing 27.1  Adding URL constants (FlickrFetchr.java)

public class FlickrFetchr {

    private static final String TAG = "FlickrFetchr";

    private static final String API_KEY = "yourApiKeyHere";
    private static final String FETCH_RECENTS_METHOD = "flickr.photos.getRecent";
    private static final String SEARCH_METHOD = "flickr.photos.search";
    private static final Uri ENDPOINT = Uri
            .parse("https://api.flickr.com/services/rest/")
            .buildUpon()
            .appendQueryParameter("api_key", API_KEY)
            .appendQueryParameter("format", "json")
            .appendQueryParameter("nojsoncallback", "1")
            .appendQueryParameter("extras", "url_s")
            .build();
    ...
    public List<GalleryItem> fetchItems() {

        List<GalleryItem> items = new ArrayList<>();

        try {
            String url = Uri.parse("https://api.flickr.com/services/rest/")
                    .buildUpon()
                    .appendQueryParameter("method", "flickr.photos.getRecent")
                    .appendQueryParameter("api_key", API_KEY)
                    .appendQueryParameter("format", "json")
                    .appendQueryParameter("nojsoncallback", "1")
                    .appendQueryParameter("extras", "url_s")
                    .build().toString();
            String jsonString = getUrlString(url);
            ...
        } catch (IOException ioe) {
            Log.e(TAG, "Failed to fetch items", ioe);
        } catch (JSONException je) {
            Log.e(TAG, "Failed to parse JSON", je);
        }

        return items;
    }
    ...
}

(The change you just made will result in an error in fetchItems(). You can ignore this error for now, as you are about to rework fetchItems() into something new anyway.)

Rename fetchItems() to downloadGalleryItems(String url) to reflect its new, more general purpose. It no longer needs to be public, either, so change its visibility to private.

Listing 27.2  Refactoring Flickr code (FlickrFetchr.java)

public class FlickrFetchr {
    ...
    public List<GalleryItem> fetchItems() {
    private List<GalleryItem> downloadGalleryItems(String url) {

        List<GalleryItem> items = new ArrayList<>();

        try {
            String jsonString = getUrlString(url);
            Log.i(TAG, "Received JSON: " + jsonString);
            JSONObject jsonBody = new JSONObject(jsonString);
            parseItems(items, jsonBody);
        } catch (IOException ioe) {
            Log.e(TAG, "Failed to fetch items", ioe);
        } catch (JSONException je) {
            Log.e(TAG, "Failed to parse JSON", je);
        }

        return items;
    }
    ...
}

The new downloadGalleryItems(String) method takes a URL as input, so there is no need to build the URL inside. Instead, add a new method to build the URL based on method and query values.

Listing 27.3  Adding helper method to build URL (FlickrFetchr.java)

public class FlickrFetchr {
    ...
    private List<GalleryItem> downloadGalleryItems(String url) {
        ...
    }

    private String buildUrl(String method, String query) {
        Uri.Builder uriBuilder = ENDPOINT.buildUpon()
                .appendQueryParameter("method", method);

        if (method.equals(SEARCH_METHOD)) {
            uriBuilder.appendQueryParameter("text", query);
        }

        return uriBuilder.build().toString();
    }

    private void parseItems(List<GalleryItem> items, JSONObject jsonBody)
            throws IOException, JSONException {
        ...
    }
}

The buildUrl(…) method appends the necessary parameters, just as fetchItems() used to. But it dynamically fills in the method parameter value. Additionally, it appends a value for the text parameter only if the value specified for the method parameter is search.

Now add methods to kick off the download by building a URL and calling downloadGalleryItems(String).

Listing 27.4  Adding methods to get recents and search (FlickrFetchr.java)

public class FlickrFetchr {
    ...
    public String getUrlString(String urlSpec) throws IOException {
        return new String(getUrlBytes(urlSpec));
    }

    public List<GalleryItem> fetchRecentPhotos() {
        String url = buildUrl(FETCH_RECENTS_METHOD, null);
        return downloadGalleryItems(url);
    }

    public List<GalleryItem> searchPhotos(String query) {
        String url = buildUrl(SEARCH_METHOD, query);
        return downloadGalleryItems(url);
    }

    private List<GalleryItem> downloadGalleryItems(String url) {
        List<GalleryItem> items = new ArrayList<>();
        ...
        return items;
    }
    ...
}

FlickrFetchr is now equipped to handle both searching and getting recent photos. The fetchRecentPhotos() and searchPhotos(String) methods serve as the public interface for getting a list of GalleryItems from the Flickr web service.

You need to update your fragment code to reflect the refactoring you just completed in FlickrFetchr. Open PhotoGalleryFragment and update FetchItemsTask.

Listing 27.5  Hardwiring search query code (PhotoGalleryFragment.java)

public class PhotoGalleryFragment extends Fragment {
    ...
    private class FetchItemsTask extends AsyncTask<Void,Void,List<GalleryItem>> {
        @Override
        protected List<GalleryItem> doInBackground(Void... params) {

            return new FlickrFetchr().fetchItems();
            String query = "robot"; // Just for testing

            if (query == null) {
                return new FlickrFetchr().fetchRecentPhotos();
            } else {
                return new FlickrFetchr().searchPhotos(query);
            }
        }

        @Override
        protected void onPostExecute(List<GalleryItem> items) {
            mItems = items;
            setupAdapter();
        }
    }
}

If the query string is not null (which for now is always the case), then FetchItemsTask will execute a Flickr search. Otherwise FetchItemsTask will default to fetching recent photos, just as it did before.

Hardcoding the query allows you to test out your new search code even though you have not yet provided a way to enter a query through the UI.

Run PhotoGallery and see what you get. Hopefully, you will see a cool robot or two (Figure 27.2).

Figure 27.2  Hardcoded search results

Screenshot shows hardcoded search results. PhotoGallery app shows a screen with thumbnails of images related to music.
..................Content has been hidden....................

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