Так получилось, что при реализации одного из моих проектов понадобился поиск изображений по определенным ключевым словам. Поиск должен был быть реализован исходя из двух простых требований:
- быть бесплатным;
- быть хорошо фильтрованным, чтобы не нарваться на проблемы с Apple (такая же задача стояла и для версии приложения под iOS).
Я долго серфил интернеты в поисках подходящего контент-провайдера, предоставляющего JSON API. В итоге были отобраны 3 основных кандидата: Google Search, Flickr и Bing Image Search. Был еще один вариант подключения к старым бесплатным API от Google, которые уже лет 5 как в статусе deprecated, но все еще работают. Но этот вариант, увы, не подходил.
К сожалению, официальные Google Search API являются, во-первых, платными, во-вторых, в результате выдачи Google по некоторым запросам вылетают неприемлемые изображения. C Bing Image Search ситуация еще более плачевная, хотя доступ к API у них обходится и дешевле.
Чтобы не быть голословным, приведу сравнение выдачи всех трех провайдеров по провокационным запросам с применением максимальной фильтрации выдачи неприемлемого контента, да простят меня автолюбители.
У Google Search, на первый взгляд, все более или менее приемлемо, но если прокрутить страницу чуть ниже, местами встречаются очень печальные картинки. У Bing Image Search все еще гораздо более хардкорно. По понятным причинам скрины этого я приводить здесь не буду. Я проводил еще множество подобных сравнений, в том числе и по пикантным запросам, и во всех них однозначным лидером оказывался Flickr. Поэтому мой выбор пал именно на него. К тому же доступ к их API является бесплатным. Единственным жирным минусом были совсем уж скудные результаты поиска на русском языке. Забегая вперед, скажу, что решено это было на бекэнде – был поднят простенький сервис, переводящий русский текст на английский. Таким образом запрос к Flickr состоял из двух частей: запрос перевода у нашего сервера, отправка полученного результата на Flickr.
Регистрация приложения
Прежде всего нам необходимо получить API key работы с Flickr. Для этого перейдем по ссылке (только для некоммерческого использования)
После заполнения формы вам будут предоставлены Key и Secret:
Интерфейс запросов к Flickr
Для начала определимся, каким образом вообще выглядит запрос к API:
http://ift.tt/1NWZ4Vh
Нам будут интересны два метода: flickr.photos.search и flickr.interestingness.getList.
Метод запроса flickr.interestingness.getList возвращает нам список самых популярных изображений. Изображения не застаиваются и периодически обновляются (по моим наблюдениям раз в пол часа — час).
Метод запроса flickr.photos.search будет использоваться непосредственно для поиска по ключевым словам.
Более подробно про каждый из параметров запроса вы можете почитать у них в официальной документации.
Пример реализации
Для реализации общения с сервисом был реализован следующий класс:
public class Flickr extends Model {
public interface FlickrModelResponseHandler {
public void onSuccess(ArrayList<HashMap<String, String>> responseArray);
public void onFailure(String error);
}
public Flickr(Context context) {
super(context);
setUrl("/services/rest/");
}
public void fetch (Map<String, String> inData, Map<String, Object> options, final FlickrModelResponseHandler handler) {
HashMap<String, String> fetchedParams = new HashMap(inData);
fetchedParams.put("api_key", "XXX");
fetchedParams.put("extras", "url_sq,url_t,url_s,url_q,url_m,url_n,url_z,url_c,url_l,url_o");
fetchedParams.put("format", "json");
fetchedParams.put("per_page", "50");
fetchedParams.put("safe_search", "safe");
fetchedParams.put("content_type", "1");
fetchedParams.put("media", "photos");
fetchedParams.put("sort", "relevance");
fetchedParams.put("license", "1,2,3,4,5,6");
super.fetch(fetchedParams, new HashMap<String, Object>() {{
put("host", "https://api.flickr.com");
}}, new ModelResponseHandler() {
@Override
public void onSuccess(Map<String, Object> responseDict) {
ArrayList<HashMap<String, String>> photos = ((HashMap<String, ArrayList<HashMap<String, String>>>)(responseDict.get("photos"))).get("photo");
if (handler != null)
handler.onSuccess(photos);
}
@Override
public void onFailure(String error) {
if (handler != null)
handler.onFailure(error);
}
});
}
@Override
protected JSONObject deserialize(String responseString) {
Pattern p = Pattern.compile(".*?\\((.*)\\)$");
Matcher m = p.matcher(responseString);
String json = null;
if (m.matches()) {
json = m.group(1);
}
JSONObject response = null;
try {
response = new JSONObject(json);
} catch (JSONException e) {
e.printStackTrace();
}
return response;
}
}
Как видно из кода выше, класс унаследован от класса Model, в котором в свою очередь реализованы примитивные методы общения с сервером (GET, POST, PUT, DELETE запросы). Метод fetch реализует http-метод GET и принимает в качестве первого аргумента параметры запроса, в качестве второго – различные флаги обработки данных и т.д., в качестве третьего – callback интерфейс.
Метод deserialize, как понятно из названия, десериализует полученные данные. Так как Flickr возвращает JSON, обернутый вот в такую бяку: jsonFlickrApi(), то перед десериализацией JSON-объекта регуляркой отбрасываем все лишнее. По остальному, я думаю, тут все понятно.
Теперь реализуем метод, в который непосредственно будет передаваться строка запроса.
private void searchImages(String query) {
HashMap<String, String> params = new HashMap<>();
flickr = new Flickr(ImageSearchActivity.this);
if (query != null) {
params.put("method", "flickr.photos.search");
params.put("text", query);
} else {
params.put("method", "flickr.interestingness.getList");
}
flickr.fetch(params, null, new Flickr.FlickrModelResponseHandler() {
@Override
public void onSuccess(ArrayList<HashMap<String, String>> responseArray) {
adapter.setArray(responseArray);
}
@Override
public void onFailure(String error) {
adapter.setArray(new ArrayList<HashMap<String, String>>());
}
});
}
Тут, если query равен null, то делаем запрос методом flickr.interestingness.getList, иначе — flickr.photos.search c текстом query.
И, напоследок, результат работы.
This entry passed through the Full-Text RSS service - if this is your content and you're reading it on someone else's site, please read the FAQ at http://ift.tt/jcXqJW.
Комментариев нет:
Отправить комментарий