Android高德地图API实现POI搜索 - Could'Joke

时间:2024-02-18 13:26:51

Android高德地图API实现POI搜索

实现效果图如下:

导入高德地图的搜索服务包到工程的libs目录中,并配置好权限与用户KEY。
权限如下:

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />  

用户KEY配置如下:

<meta-data 
     android:name="com.amap.api.v2.apikey"
     android:value="这里填你的KEY"/>  

创建activity_main.xml布局文件如下,因为要实现用户输入直接就显示数据,所以就没用到搜索按钮。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >
    <EditText 
        android:id="@+id/search_edit"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
    <ListView 
        android:id="@+id/search_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content">
        
    </ListView>
</LinearLayout>

创建address_item.xml布局文件如下,用于ListView中每一个Item布局。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:padding="20dp" >
    <TextView 
        android:id="@+id/item_title"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="标题"
        android:textSize="20sp"/>
    <TextView 
        android:id="@+id/item_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="内容"
        android:textColor="#FF4A4A4A"/>
</LinearLayout>  

创建AddressBean实体类,代码如下

   public class AddressBean {
    private double longitude;//经度
    private double latitude;//纬度
    private String title;//信息标题
    private String text;//信息内容
    public AddressBean(double lon, double lat, String title, String text){
        this.longitude = lon;
        this.latitude = lat;
        this.title = title;
        this.text = text;
    }
    public double getLongitude() {
        return longitude;
    }
    
    public double getLatitude() {
        return latitude;
    }
    public String getTitle() {
        return title;
    }
    public String getText(){
        return text;
    }
}

创建SearchAdapter数据适配器类,代码如下:

public class SearchAdapter extends BaseAdapter{
    private List<AddressBean> data;
    private LayoutInflater li;
    public SearchAdapter(Context context){
        li = LayoutInflater.from(context);
    }
    
    /**
     * 设置数据集
     * @param data
     */
    public void setData(List<AddressBean> data){
        this.data = data;
    }
    
    @Override
    public int getCount() {
        return data.size();
    }
    @Override
    public Object getItem(int position) {
        return data.get(position);
    }
    @Override
    public long getItemId(int position) {
        return position;
    }
    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ViewHolder vh = null;
        if(convertView == null){
            vh = new ViewHolder();
            convertView = li.inflate(R.layout.address_item, null);
            vh.title = (TextView) convertView.findViewById(R.id.item_title);
            vh.text = (TextView) convertView.findViewById(R.id.item_text);
            convertView.setTag(vh);
        }else{
            vh = (ViewHolder) convertView.getTag();
        }
        vh.title.setText(data.get(position).getTitle());
        vh.text.setText(data.get(position).getText());
        return convertView;
    }
    
    private class ViewHolder{
        public TextView title;
        public TextView text;
    }
}

这里会提供方法setData()用于动态更新数据集。

创建InputTask类,封装PoiSearch的搜索服务,并与Adapter进行绑定。

public class InputTask implements OnPoiSearchListener {
    private static InputTask mInstance;
    private SearchAdapter mAdapter;
    private PoiSearch mSearch;
    private Context mContext;
    private InputTask(Context context, SearchAdapter adapter){
        this.mContext = context;
        this.mAdapter = adapter;
    }
    /**
     * 获取实例
     * @param context 上下文
     * @param adapter 数据适配器
     * @return
     */
    public static InputTask getInstance(Context context, SearchAdapter adapter){
        if(mInstance == null){
            synchronized (InputTask.class) {
                if(mInstance == null){
                    mInstance = new InputTask(context, adapter);
                }
            }
        }
        return mInstance;
    }
    /**
     * 设置数据适配器
     * @param adapter
     */
    public void setAdapter(SearchAdapter adapter){
        this.mAdapter = adapter;
    }
    /**
     * POI搜索
     * @param key 关键字
     * @param city 城市
     */
    public void onSearch(String key, String city){
        //POI搜索条件
        PoiSearch.Query query = new PoiSearch.Query(key, "", city);
        mSearch = new PoiSearch(mContext, query);
        //设置异步监听
        mSearch.setOnPoiSearchListener(this);
        //查询POI异步接口
        mSearch.searchPOIAsyn();
    }
    /**
     * 异步搜索回调
     */
    @Override
    public void onPoiSearched(PoiResult poiResult, int rCode) {
        if(rCode == 0 && poiResult != null){
            ArrayList<AddressBean> data = new ArrayList<AddressBean>();
            ArrayList<PoiItem> items = poiResult.getPois();
            for(PoiItem item : items){
                //获取经纬度对象
                LatLonPoint llp = item.getLatLonPoint();
                double lon = llp.getLongitude();
                double lat = llp.getLatitude();
                //获取标题
                String title = item.getTitle();
                //获取内容
                String text = item.getSnippet();
                data.add(new AddressBean(lon, lat, title, text));
            }
            mAdapter.setData(data);
            mAdapter.notifyDataSetChanged();
        }
    }
}  

使用PoiSearch.Query定义搜索条件,构造方法有三个参数分别是:搜索关键字、POI类别、城市(地区)。
其中多个关键字用“|”分割,POI类别可以为""空字符串代表不区分类别,城市可以为""空字符串代表检索所有城市。
在搜索到结果回调的时候使用notifyDataSetChanged()更新数据适配器,实现数据动态更新。

创建MainAty类,代码如下:

public class MainAty extends Activity implements TextWatcher, OnItemClickListener{
    private static final String TAG = "MainAty";
    private EditText edit;
    private ListView lv;
    private SearchAdapter mAdapter;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();
    }
    private void initView(){
        edit = (EditText) findViewById(R.id.search_edit);
        lv = (ListView) findViewById(R.id.search_list);
        edit.addTextChangedListener(this);
        mAdapter = new SearchAdapter(this);
        lv.setAdapter(mAdapter);
    }
    @Override
    public void beforeTextChanged(CharSequence s, int start, int count,
            int after) {
        
    }
    @Override
    public void onTextChanged(CharSequence s, int start, int before, int count) {
        InputTask.getInstance(this, mAdapter).onSearch(s.toString(), "");
    }
    @Override
    public void afterTextChanged(Editable s) {
        
    }
    @Override
    public void onItemClick(AdapterView<?> parent, View view, int position,
            long id) {
        //Item点击事件处理
    }
}  

实现TextWatcher,并重写onTextChanged方法监听输入框数据的变化,从而实现实时更新数据。