You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为Places自动完成碎片添加搜索历史功能

如何为Places自动完成碎片添加搜索历史功能

嘿,这个需求挺实用的!我来给你分享几个简单可行的实现思路,帮你给你的地图搜索加上最近搜索记录的功能~

方案一:用SharedPreferences存储历史记录(轻量易实现)

SharedPreferences是Android里存储轻量数据的绝佳选择,适合保存搜索历史这种简单的列表数据。我们可以在用户选择地点后把相关信息存起来,之后再读取并展示。

步骤1:添加存储和读取历史的工具方法

先写两个工具方法,一个用来保存选中的地点到历史,另一个用来读取已有的历史记录。可以把这些方法放在你的Activity或者单独的工具类里:

// 保存搜索历史到SharedPreferences
private void saveSearchHistory(Place place) {
    SharedPreferences prefs = getSharedPreferences("SearchHistory", MODE_PRIVATE);
    SharedPreferences.Editor editor = prefs.edit();
    
    // 先获取已有的历史列表
    Set<String> historySet = prefs.getStringSet("history", new HashSet<>());
    // 把地点信息拼接成字符串(用分隔符分开名称、纬度、经度)
    String placeInfo = place.getName() + "|" + place.getLatLng().latitude + "|" + place.getLatLng().longitude;
    
    // 去重:如果已存在就先移除,再添加到最前面(保证最新记录在顶部)
    historySet.remove(placeInfo);
    historySet.add(placeInfo);
    
    // 最多保存10条历史,可根据需求调整数量
    if (historySet.size() > 10) {
        Iterator<String> iterator = historySet.iterator();
        iterator.next();
        iterator.remove();
    }
    
    editor.putStringSet("history", historySet);
    editor.apply();
}

// 读取搜索历史
private List<Map<String, Object>> getSearchHistory() {
    SharedPreferences prefs = getSharedPreferences("SearchHistory", MODE_PRIVATE);
    Set<String> historySet = prefs.getStringSet("history", new HashSet<>());
    List<Map<String, Object>> historyList = new ArrayList<>();
    
    for (String placeInfo : historySet) {
        String[] parts = placeInfo.split("\\|");
        if (parts.length == 3) {
            Map<String, Object> placeMap = new HashMap<>();
            placeMap.put("name", parts[0]);
            placeMap.put("latitude", Double.parseDouble(parts[1]));
            placeMap.put("longitude", Double.parseDouble(parts[2]));
            historyList.add(placeMap);
        }
    }
    
    // 反转列表,让最新的记录在最前面
    Collections.reverse(historyList);
    return historyList;
}

步骤2:在选择地点时保存历史

修改你现有的onPlaceSelected方法,在里面调用保存历史的方法:

@Override
public void onPlaceSelected(@NonNull Place place) {
    // 原有的代码不变...
    Log.i(TAG, "Place: " + place.getName() + ", " + place.getId());
    LatLng selectedPlaceLatLng = place.getLatLng();
    // ...(其他地图操作代码)
    
    // 新增:保存当前选择的地点到历史
    saveSearchHistory(place);
}

步骤3:展示历史记录

接下来把历史记录展示给用户,最简单的方式是在AutocompleteSupportFragment上方添加一个RecyclerView,用来显示最近的搜索记录。

  1. 修改布局文件(比如activity_main.xml):
<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <!-- 搜索历史列表 -->
    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/history_recycler"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:visibility="gone"/>

    <!-- 原有的Autocomplete碎片 -->
    <fragment
        android:id="@+id/autocomplete_fragment"
        android:name="com.google.android.libraries.places.widget.AutocompleteSupportFragment"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"/>
</LinearLayout>
  1. 在Activity里初始化RecyclerView,设置适配器,并监听搜索框焦点来显示/隐藏历史:
private RecyclerView historyRecycler;
private HistoryAdapter historyAdapter;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    // 初始化RecyclerView
    historyRecycler = findViewById(R.id.history_recycler);
    historyRecycler.setLayoutManager(new LinearLayoutManager(this));
    historyAdapter = new HistoryAdapter(getSearchHistory(), place -> {
        // 点击历史项时执行和选择地点一样的逻辑
        LatLng selectedLatLng = new LatLng((double) place.get("latitude"), (double) place.get("longitude"));
        CameraPosition cameraPosition = new CameraPosition.Builder()
                .target(selectedLatLng)
                .zoom(20)
                .build();
        mMap.animateCamera(CameraUpdateFactory.newCameraPosition(cameraPosition));
        
        if (markerSelectedLoc != null) {
            markerSelectedLoc.remove();
        }
        markerSelectedLoc = mMap.addMarker(new MarkerOptions()
                .position(selectedLatLng)
                .flat(true));
        
        checkDistanceToCustomRoutes(selectedLatLng, mlocation);
    });
    historyRecycler.setAdapter(historyAdapter);
    
    // 监听搜索框焦点变化,显示/隐藏历史
    autocompleteFragment.getView().findViewById(R.id.places_autocomplete_search_input).setOnFocusChangeListener((v, hasFocus) -> {
        if (hasFocus && !getSearchHistory().isEmpty()) {
            historyRecycler.setVisibility(View.VISIBLE);
        } else {
            historyRecycler.setVisibility(View.GONE);
        }
    });
    
    // 原有的Places初始化代码...
}

// 自定义RecyclerView适配器
private class HistoryAdapter extends RecyclerView.Adapter<HistoryAdapter.ViewHolder> {
    private List<Map<String, Object>> historyList;
    private OnHistoryItemClickListener listener;
    
    public interface OnHistoryItemClickListener {
        void onHistoryItemClick(Map<String, Object> place);
    }
    
    public HistoryAdapter(List<Map<String, Object>> historyList, OnHistoryItemClickListener listener) {
        this.historyList = historyList;
        this.listener = listener;
    }
    
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_history, parent, false);
        return new ViewHolder(view);
    }
    
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        Map<String, Object> place = historyList.get(position);
        holder.placeName.setText((String) place.get("name"));
        holder.itemView.setOnClickListener(v -> listener.onHistoryItemClick(place));
    }
    
    @Override
    public int getItemCount() {
        return historyList.size();
    }
    
    public class ViewHolder extends RecyclerView.ViewHolder {
        TextView placeName;
        
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
            placeName = itemView.findViewById(R.id.place_name);
        }
    }
}
  1. 创建item_history.xml布局文件(单条历史记录的样式):
<TextView
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/place_name"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:textSize="16sp"
    android:background="?attr/selectableItemBackground"/>

方案二:自定义Autocomplete视图(更灵活)

如果你希望把历史记录直接整合到Google Places的自动建议列表里,那需要自定义整个搜索框和建议列表,而不是用官方的AutocompleteSupportFragment。这种方式灵活性更高,但代码量更大,需要自己实现搜索框,然后合并本地历史和Places的搜索结果后展示。

不过对于大多数场景来说,方案一已经足够好用,而且实现起来快很多~

额外小建议

  • 可以给历史记录添加删除按钮,让用户手动清除不需要的记录
  • 如果需要保存更详细的地点信息,可用Gson把Place对象转成Json字符串存储,读取时再解析回来
  • SharedPreferences不需要额外权限,不用担心权限问题

备注:内容来源于stack exchange,提问作者Chichi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.21 12:13:00