package net.coding.program.maopao; import android.content.Context; import android.text.TextUtils; import android.util.Log; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.JsonHttpResponseHandler; import com.loopj.android.http.RequestParams; import net.coding.program.AllThirdKeys; import net.coding.program.model.AccountInfo; import net.coding.program.model.LocationObject; import net.coding.program.model.UserObject; import org.apache.http.Header; import org.json.JSONArray; import org.json.JSONObject; import java.io.UnsupportedEncodingException; import java.net.URLEncoder; import java.security.MessageDigest; import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Map.Entry; public class BaiduLbsLoader { private static final String host = "http://api.map.baidu.com"; private static final int PAGE_SIZE = 20; // 每页数量10~20,超过20服务器也只会返回20个 private static final String RADIUS = "2000"; private static String getUserId(Context context) { UserObject userObject = AccountInfo.loadAccount(context); return userObject == null ? "" : String.valueOf(userObject.id); } public static void searchCustom(Context context, String keyword, double latitude, double longitude, final int page, final LbsResultListener listener) { final String path = "/geosearch/v3/nearby"; LinkedHashMap<String, String> params = new LinkedHashMap<>(); params.put("ak", AllThirdKeys.ak); UserObject userObject = AccountInfo.loadAccount(context); if (userObject != null) { params.put("filter", String.format("user_id:[%d]", userObject.id)); } params.put("geotable_id", AllThirdKeys.geotable); params.put("q", keyword); params.put("location", String.format("%f,%f", longitude, latitude)); params.put("pageIndex", String.valueOf(page)); params.put("pageSize", String.valueOf(PAGE_SIZE)); params.put("radius", "1000"); params.put("sortby", "distance:1 "); String url; try { url = host + path + "?" + queryString(params) + "&sn=" + sn(path, params); } catch (UnsupportedEncodingException e) { Log.e("BaiduLbsLoader", "get url error", e); return; } AsyncHttpClient client = new AsyncHttpClient(); final int searchPos = LocationSearchActivity.getSearchPos(); client.get(context, url, new SearchResponseHandler(listener) { @Override protected LocationObject parseItem(JSONObject json) { if (json == null) return null; String id = json.optString("uid"); String name = json.optString("title"); String address = json.optString("address"); LocationObject object = new LocationObject(id, name, address); JSONArray location = json.optJSONArray("location"); if (location != null && location.length() == 2) { object.longitude = location.optDouble(0, 0); object.latitude = location.optDouble(1, 0); } object.distance = json.optInt("distance"); return object; } @Override protected void parseResult(JSONObject json, LbsResultListener listener) { int lastPage = (json.optInt("total", 0) + PAGE_SIZE - 1) / PAGE_SIZE - 1; JSONArray array = json.optJSONArray("contents"); if (searchPos == LocationSearchActivity.getSearchPos()) { listener.onSearchResult(true, parseList(array), page < lastPage && array.length() >= PAGE_SIZE); } } }); } // sdk的PoiSearch不支持多关键字搜索,所以用webapi实现 public static void searchPublic(Context context, String keyword, double latitude, double longitude, final int page, final LbsResultListener listener) { final String path = "/place/v2/search"; LinkedHashMap<String, String> params = new LinkedHashMap<>(); params.put("ak", AllThirdKeys.ak); params.put("location", String.format("%f,%f", latitude, longitude)); params.put("output", "json"); params.put("page_num", String.valueOf(page)); params.put("page_size", String.valueOf(PAGE_SIZE)); params.put("query", keyword); // 经测试,复合查询只能用query而不能用q params.put("radius", RADIUS); params.put("scope", "1"); String url = buildUrl(path, params); if (url == null) { listener.onSearchResult(false, null, false); return; } final int searchPos = LocationSearchActivity.getSearchPos(); AsyncHttpClient client = new AsyncHttpClient(); client.get(context, url, new SearchResponseHandler(listener) { @Override protected LocationObject parseItem(JSONObject json) { if (json == null) return null; String id = json.optString("uid"); String name = json.optString("name"); String address = json.optString("address"); LocationObject object = new LocationObject(id, name, address); JSONObject location = json.optJSONObject("location"); if (location != null) { object.latitude = location.optDouble("lat", 0); object.longitude = location.optDouble("lng", 0); } object.distance = json.optInt("distance"); return object; } @Override protected void parseResult(JSONObject json, LbsResultListener listener) { int lastPage = (json.optInt("total", 0) + PAGE_SIZE - 1) / PAGE_SIZE - 1; JSONArray array = json.optJSONArray("results"); if (searchPos == LocationSearchActivity.getSearchPos()) { listener.onSearchResult(true, parseList(array), page < lastPage && array.length() >= PAGE_SIZE); } } }); } private static String buildUrl(String path, LinkedHashMap<String, String> params) { try { return host + path + "?" + queryString(params) + "&sn=" + sn(path, params); } catch (Exception e) { Log.e("BaiduLbsLoader", "build url error", e); return null; } } public static void store(Context context, String name, String address, double latitude, double longitude, final StorePoiListener listener) { final String path = "/geodata/v3/poi/create"; LinkedHashMap<String, String> params = new LinkedHashMap<>(); params.put("address", address); params.put("ak", AllThirdKeys.ak); params.put("coord_type", "3"); params.put("geotable_id", AllThirdKeys.geotable); params.put("latitude", String.valueOf(latitude)); params.put("longitude", String.valueOf(longitude)); params.put("title", name); params.put("user_id", getUserId(context)); try { params.put("sn", sn(path, params)); } catch (UnsupportedEncodingException e) { Log.e("BaiduLbsLoader", "get url error", e); return; } AsyncHttpClient client = new AsyncHttpClient(); client.post(context, host + path, new RequestParams(params), new JsonHttpResponseHandler() { @Override public void onSuccess(int statusCode, Header[] headers, JSONObject json) { String id = null; boolean success = json != null && !TextUtils.isEmpty(id = json.optString("id")); if (listener != null) listener.onStoreResult(success, id); } @Override public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) { if (listener != null) listener.onStoreResult(false, null); } @Override public void onSuccess(int statusCode, Header[] headers, String responseString) { if (listener != null) listener.onStoreResult(false, null); } }); } private static String sn(String path, LinkedHashMap<String, String> params) throws UnsupportedEncodingException { return md5(URLEncoder.encode(path + "?" + queryString(params) + AllThirdKeys.sk, "UTF-8")); } private static String queryString(Map<?, ?> data) throws UnsupportedEncodingException { StringBuffer qs = new StringBuffer(); for (Entry<?, ?> pair : data.entrySet()) { qs.append(pair.getKey() + "="); qs.append(URLEncoder.encode((String) pair.getValue(), "UTF-8") + "&"); } if (qs.length() > 0) { qs.deleteCharAt(qs.length() - 1); } return qs.toString(); } private static String md5(String src) { try { byte[] array = MessageDigest.getInstance("MD5").digest(src.getBytes()); StringBuffer sb = new StringBuffer(); for (byte anArray : array) { sb.append(Integer.toHexString((anArray & 0xFF) | 0x100).substring(1, 3)); } return sb.toString(); } catch (java.security.NoSuchAlgorithmException e) { return null; } } public interface LbsResultListener { void onSearchResult(boolean success, List<LocationObject> list, boolean hasMore); } public interface StorePoiListener { void onStoreResult(boolean success, String id); } private static abstract class SearchResponseHandler extends JsonHttpResponseHandler { private LbsResultListener listener; SearchResponseHandler(LbsResultListener listener) { this.listener = listener; } protected abstract LocationObject parseItem(JSONObject json); protected abstract void parseResult(JSONObject json, LbsResultListener listener); protected List<LocationObject> parseList(JSONArray array) { ArrayList<LocationObject> list = new ArrayList<>(); if (array != null) { for (int i = 0, c = array.length(); i < c; ++i) { LocationObject item = parseItem(array.optJSONObject(i)); if (item != null) list.add(item); } } return list; } @Override public void onSuccess(int statusCode, Header[] headers, JSONObject json) { if (json == null || json.optInt("status") != 0) { if (listener != null) listener.onSearchResult(false, null, false); } else if (listener != null) { parseResult(json, listener); } } @Override public void onFailure(int statusCode, Header[] headers, Throwable throwable, JSONObject errorResponse) { if (listener != null) listener.onSearchResult(false, null, false); } @Override public void onSuccess(int statusCode, Header[] headers, String responseString) { if (listener != null) listener.onSearchResult(false, null, false); } } }