Android正确实现SearchView 解决ListView过滤后点击跳转错误
问题根因
- 核心逻辑错误:点击事件硬编码用列表当前显示位置
position匹配原始地点数组索引。SearchView触发过滤后,ArrayAdapter仅展示符合搜索条件的条目子集,此时回调的position是过滤后列表的位置,和原始数组的索引完全不匹配。比如搜索"Fourth Location"时,列表仅展示这1个条目,它在过滤后列表的position为0,代码判断position==0就会跳转第一个地点的坐标,必然出错。 - 语法隐患:原有代码最后一个if条件块缺少闭合右括号,编译阶段就可能报错。
- 细节问题:原有geo协议URI里
geo:后多了空格,部分设备会解析失败。
修复步骤
1. 定义实体类绑定地点名称和坐标
不要分开维护名称数组、硬编码坐标判断,把每个地点的名称、对应跳转URI绑定成一个对象,从根源避免索引错位:
public class LocationItem { private String name; private String geoUri; public LocationItem(String name, String geoUri) { this.name = name; this.geoUri = geoUri; } public String getName() { return name; } public String getGeoUri() { return geoUri; } // 重写toString,让ArrayAdapter默认显示地点名称 @Override public String toString() { return name; } }
2. 替换原有字符串数组,用实体列表初始化适配器
把原来的字符串数组成员替换成实体列表,初始化时把每个地点的名称、坐标一一对应:
// 替换Activity里的原有成员变量定义 ListView listView; List<LocationItem> locationList = new ArrayList<>(); ArrayAdapter<LocationItem> arrayAdapter; @Override protected void onCreate(Bundle savedInstanceState) { // 省略原有ActionBar、setContentView相关代码... listView = findViewById(R.id.listview); // 初始化地点数据 locationList.add(new LocationItem("First Location", "geo:21.422458,39.826213")); locationList.add(new LocationItem("Second Location", "geo:24.467275,39.610629")); locationList.add(new LocationItem("Third Location", "geo:25.173059,45.142079")); locationList.add(new LocationItem("Fourth Location", "geo:26.348400,43.766664")); arrayAdapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, locationList); listView.setAdapter(arrayAdapter);
3. 重写点击事件逻辑,废弃硬编码位置判断
点击时直接从适配器当前显示的列表里取对应条目,不管过滤前后列表怎么变,都能拿到当前点击项的正确坐标:
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { LocationItem clickedItem = (LocationItem) parent.getItemAtPosition(position); Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(clickedItem.getGeoUri())); startActivity(intent); } }); // 补全onCreate方法的闭合括号 }
搜索过滤的逻辑不用改,原有arrayAdapter.getFilter().filter(newText)可以正常工作。
修复原理
ArrayAdapter执行过滤时,会把符合搜索条件的条目单独存到内部的临时显示列表,点击事件返回的position永远对应当前屏幕展示的过滤后列表位置,和原始全量数据列表的索引没有绑定关系。直接通过getItemAtPosition(position)取当前展示的条目对象,不依赖硬编码的索引映射,无论怎么搜索过滤,都能拿到用户实际点击的地点数据,不会再出现跳转错位的问题。
内容的提问来源于stack exchange,提问作者imacro
相关产品推荐
相关产品推荐

