【Android】模糊搜索与数据处理

【Android】模糊搜索与数据处理本篇博客主要以根据输入内容动态获取城市为例进行讲解

大家好,欢迎来到IT知识分享网。

【Android】模糊搜索与数据处理

本篇博客主要以根据输入内容动态获取城市为例进行讲解。

获取城市

这一部分主要是根据输入的信息去动态获取城市信息

首先定义了一个名为 NetUtil 的类,主要用于通过 HTTP 请求获取城市信息。

public class NetUtil { 
    private static final String URL_CITY_DAY = "https://geoapi.qweather.com/v2/city/lookup?"; private static final String API_KEY = ""; public static String doGet(String urlStr) throws IOException { 
    String result = ""; try { 
    OkHttpClient client = new OkHttpClient(); Request request = new Request.Builder() .url(urlStr) .build(); Response response = client.newCall(request).execute(); result = response.body().string(); } catch (IOException e) { 
    throw new RuntimeException(e); } finally { 
    return result; } } public static String getCitys(String name) throws IOException { 
    String weatherUrl = URL_CITY_DAY + "location=" + name + "&key=" + API_KEY + "&range=cn"; String cityResult = doGet(weatherUrl); return cityResult; } } 

URL 定义

  • URL_WEATHER 是一个常量,定义了用于获取天气信息的 API URL。这个 API 来自“易客天气”平台。
  • URL_CITY_DAY 是另一个常量,定义了查询城市的 API URL。这个 API 来自“和风天气”平台。
  • API_KEY 用于存放和风天气的 API 密钥,但是目前是空的,需要填入实际的 API 密钥才能使用。

doGet 方法

  • 这个方法用于发起 HTTP GET 请求。
  • 使用了 OkHttp 库来发送请求,urlStr 是请求的 URL。
  • 方法首先创建一个 OkHttpClient 对象,然后构建一个 Request,并使用 client.newCall(request).execute() 来执行该请求。
  • 请求的响应 (Response) 通过 response.body().string() 获取响应内容,将其存储到 result 变量中。
  • 如果在请求过程中发生异常,会捕获 IOException 并抛出一个 RuntimeException
  • 最后,无论是否有异常,都会返回 result,即请求的响应结果。

getCitys 方法

  • 这个方法用于根据城市名称查询城市的相关信息。
  • 首先,它将城市名 name 通过 URL 参数形式与 API 密钥和 range=cn 参数一起拼接成完整的 API URL,目的是查询中国范围内的城市。
  • 然后,它调用 doGet 方法来发送请求,并获取请求的响应内容 cityResult
  • 最后,记录获取到的响应数据,并返回查询结果 cityResult

下面我们要在MainActivity中去实现根据输入信息发起网络请求,并通过异步线程获取该输入文字相关的城市数据:

private void fetchCitys(String city) { 
    if (city == null || city.trim().isEmpty()) { 
    return; // 如果输入为空,不进行网络请求 } new Thread(() -> { 
    try { 
    String weatherOfCity = NetUtil.getCitys(city); if (weatherOfCity != null) { 
    Message message = Message.obtain(); message.what = 0; message.obj = weatherOfCity; mHandler.sendMessage(message); // 将获取到的城市数据通过Handler发送到主线程 } else { 
    runOnUiThread(() -> Toast.makeText(SearchForCitysActivity.this, "未能获取到城市数据", Toast.LENGTH_SHORT).show()); } } catch (IOException e) { 
    e.printStackTrace(); runOnUiThread(() -> Toast.makeText(SearchForCitysActivity.this, "网络请求失败:" + e.getMessage(), Toast.LENGTH_SHORT).show()); } }).start(); } 
private Handler mHandler = new Handler(Looper.getMainLooper()) { 
    @Override public void handleMessage(@NonNull Message msg) { 
    if (msg.what == 0) { 
    String city = (String) msg.obj; if (city == null) { 
    Toast.makeText(SearchForCitysActivity.this, "网络请求失败!!", Toast.LENGTH_SHORT).show(); return; } parseToCityString(city); cityItemRecyclerView.getAdapter().notifyDataSetChanged(); } } }; 

获取到了 JSON 格式的城市数据,下面我们定义了一个名为 parseToCityString 的方法,负责解析从 API 返回的城市信息 JSON 数据,并将其转换为一个城市信息列表:

private void parseToCityString(String cityJson) { 
    List<String> cityList = new ArrayList<>(); // 将 JSON 字符串解析为 JsonObject JsonObject jsonObject = JsonParser.parseString(cityJson).getAsJsonObject(); // 获取 "location" 数组 JsonArray jsonArray = jsonObject.getAsJsonArray("location"); if (jsonArray == null) { 
    Log.e(TAG, "Location array is null"); runOnUiThread(() -> Toast.makeText(SearchForCitysActivity.this, "未能获取到城市信息", Toast.LENGTH_SHORT).show()); return; } // 遍历数组中的每个元素 for (JsonElement jsonElement : jsonArray) { 
    JsonObject cityObject = jsonElement.getAsJsonObject(); // 获取城市名称和行政区信息 String name = cityObject.get("name").getAsString(); String adm1 = cityObject.get("adm1").getAsString(); String adm2 = cityObject.get("adm2").getAsString(); // 组合为所需的格式 String cityInfo = name + "——" + adm1 + "——" + adm2; cityList.add(cityInfo); } citys = cityList; runOnUiThread(() -> { 
    SearchCityItemsAdapter adapter = (SearchCityItemsAdapter) cityItemRecyclerView.getAdapter(); if (adapter != null) { 
    adapter.updateCityList(citys); } }); } 

初始化城市列表

  • 创建一个空的 cityList,用于存储解析出来的城市信息字符串。

解析 JSON 字符串

  • 使用 JsonParser.parseString 方法将传入的 cityJson 字符串转换为 JsonObject。这个对象包含从服务器获取的城市数据。

获取 “location” 数组

  • JsonObject 中提取名为 "location" 的数组,它包含多个城市的信息。每个元素代表一个城市的数据。

检测数据有效性

  • 检查 "location" 数组是否为 null。如果是 null,表示服务器没有返回有效的城市数据。此时通过记录日志和在主线程显示 Toast 提示用户,通知未能获取到城市信息,并结束方法的执行。

解析每个城市的信息

  • 遍历 "location" 数组中的每个元素。每个元素都是一个包含城市信息的 JsonObject
  • 从每个城市的 JsonObject 中提取城市名称(name)、省级行政区(adm1)和地级行政区(adm2)。
  • 将提取的信息组合成一个字符串,格式为 城市名——省级行政区——地级行政区,并将其添加到 cityList 中。

保存解析结果

  • 将生成的 cityList 赋值给类的成员变量 citys,这使得其他部分可以访问到最新的城市数据。

更新 UI

  • 使用 runOnUiThread 将解析后的城市信息更新到 UI 中。因为 UI 操作只能在主线程上进行,所以通过这个方法确保在主线程执行更新操作。
  • 获取 RecyclerView 的适配器 SearchCityItemsAdapter,并调用适配器的 updateCityList(citys) 方法,传入最新的城市列表,更新 RecyclerView 中的城市列表显示。

现在我们就把根据输入的信息去搜索相应的城市就实现了,下面我们就要开始进行数据处理了。

数据处理与信息传递

SearchView

下面大致说一下SearchView用法:

SearchView 的主要功能是为用户提供一个搜索输入框,通常用于在应用中实现搜索功能。以下是其核心功能:

  1. 搜索输入:允许用户输入搜索关键词。
  2. 实时建议:支持根据用户输入的关键词动态提供搜索建议。
  3. 语音搜索:可以配置成支持语音输入功能(需要设备支持)。
  4. 图标化显示:可以在初始状态下以搜索图标的形式显示,用户点击图标时展开为输入框。
  5. 提交搜索请求:当用户输入完查询后,可以点击提交按钮或键盘上的回车键触发搜索请求。
  6. 显示占位提示:可以设置 queryHint 来显示输入提示,引导用户输入。

我们在使用的时候,主要使用的是监控输入的信息。

在创建searchView并获取实例后,可以设置监听事件:

searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() { 
    @Override public boolean onQueryTextSubmit(String query) { 
    return true; } @Override public boolean onQueryTextChange(String newText) { 
    fetchCitys(newText); // 调用获取城市的方法 return true; } }); 

onQueryTextSubmit(String query) 这个方法在用户提交搜索请求时触发,即用户输入完关键词并按下“提交”键(通常是键盘上的回车键)在这个方法中,你可以处理用户的完整搜索请求,比如开始执行搜索或查询操作。

onQueryTextChange(String newText) 这个方法在用户每次修改搜索框内容时触发,比如用户键入或删除字符时。通常用于实现实时搜索或提供动态建议。

我们在进行模糊搜索的时候就要使用的是onQueryTextChange()这个方法,这里我们调用了上面的fetchCitys()去获取相关的城市。

RecyclerView绑定

我们获取了输入信息所对应的城市之后,就需要把相应的信息显示在搜索框下面,我们这里就需要使用到RecyclerView。

当然,我们并不能仅仅只创建一个简单的RecyclerView,因为我们会对想要查询的城市进行点击,所以要设置点击事件,并且还需要把选中的城市返回到Activity方便进行其他操作。

先创建Adapter:

public class SearchCityItemsAdapter extends RecyclerView.Adapter<SearchCityItemsAdapter.SearchCityItemsViewHolder> { 
    List<String> citys; private OnItemClickListener onItemClickListener; // 定义点击事件接口 public interface OnItemClickListener { 
    void onItemClick(String cityInfo); } // 构造函数中传入点击监听器 public SearchCityItemsAdapter(List<String> citys, OnItemClickListener listener) { 
    this.citys = citys; this.onItemClickListener = listener; } @NonNull @Override public SearchCityItemsAdapter.SearchCityItemsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 
    View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.city_recyclerview_item, parent, false); return new SearchCityItemsViewHolder(view); } @Override public void onBindViewHolder(@NonNull SearchCityItemsAdapter.SearchCityItemsViewHolder holder, int position) { 
    String cityInfo = citys.get(position); holder.cityItem.setText(cityInfo); // 设置点击事件 holder.itemView.setOnClickListener(v -> { 
    if (onItemClickListener != null) { 
    onItemClickListener.onItemClick(cityInfo); } }); } @Override public int getItemCount() { 
    return citys == null ? 0 : citys.size(); } public class SearchCityItemsViewHolder extends RecyclerView.ViewHolder { 
    TextView cityItem; public SearchCityItemsViewHolder(@NonNull View itemView) { 
    super(itemView); cityItem = itemView.findViewById(R.id.cityName_item); } } public void updateCityList(List<String> newCityList) { 
    this.citys = newCityList; notifyDataSetChanged(); } } 

我们自定义了一个点击事件监听器接口 OnItemClickListener,并在 RecyclerView.Adapter 中传递了这个监听器。

上面代码我们可以实现点击RecyclerView中的item后,通过 onItemClickListener.onItemClick(cityInfo);,我们就可以在Activity中获取点击的城市名称。

Activity中实现如下:

 cityItemRecyclerView = findViewById(R.id.search_recyclerview); LinearLayoutManager layoutManager1 = new LinearLayoutManager(this); cityItemRecyclerView.setLayoutManager(layoutManager1); // 创建适配器并传入点击事件监听器 SearchCityItemsAdapter adapter = new SearchCityItemsAdapter(citys, new SearchCityItemsAdapter.OnItemClickListener() { 
    @Override public void onItemClick(String cityInfo) { 
    Intent intent1 = new Intent(SearchForCitysActivity.this, AddCityActivity.class); intent1.putExtra("CityName", cityInfo); intent1.putStringArrayListExtra("CityNames", (ArrayList<String>) cityNames); startActivity(intent1); } }); cityItemRecyclerView.setAdapter(adapter); 

我们在创建RecyclerView的Adapter的时候就创建了点击事件监听器,重写了onItemClick(String cityInfo)方法,使我们在点击item后可以把城市名称传递给下一个活动。


这样我们就完整实现了模糊搜索与数据处理。


已经到底啦!!

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/133917.html

(0)
上一篇 2025-07-16 18:33
下一篇 2025-07-16 18:45

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信