gpt4 book ai didi

Android AutocompleteTextView 使用 ArrayAdapter 和 Filter

转载 作者:IT老高 更新时间:2023-10-28 22:15:20 25 4
gpt4 key购买 nike

背景资料

我目前正在编写的应用程序处理地点。创建地点的主要方法是输入地址。为用户体验提供一种方便的方式非常重要。

当前解决方案

在调查了一段时间后,我得出的结论是,最好的方法是基于当前位置和用户输入(如在 Google map 应用程序中)自动完成的文本区域。由于很遗憾 Google Map API 没有提供此功能,因此我必须自己实现它。

当前实现

要获得地址建议,我使用 Geocoder .这些建议提供给 AutoCompleteTextView通过自定义 ArrayAdaptor通过自定义Filter .

ArrayAdapter(部分代码已被删除)

public class AddressAutoCompleteAdapter extends ArrayAdapter<Address> {

@Inject private LayoutInflater layoutInflater;

private ArrayList<Address> suggested;
private ArrayList<Address> lastSuggested;
private String lastInput = null;
private AddressLoader addrLoader;

public AddressAutoCompleteAdapter(Activity activity,
AddressLoaderFactory addrLoaderFact,
int maxSuggestionsCount) {
super(activity,R.layout.autocomplete_address_item);
suggested = new ArrayList<Address>();
lastSuggested = new ArrayList<Address>();
addrLoader = addrLoaderFact.create(10);
}

...

@Override
public Filter getFilter() {
Filter myFilter = new Filter() {

...

@SuppressWarnings("unchecked")
@Override
protected FilterResults performFiltering(CharSequence constraint) {
Log.d("MyPlaces","performFiltring call");
FilterResults filterResults = new FilterResults();
boolean debug = false;
if(constraint != null) {
// Load address
try {
suggested = addrLoader.load(constraint.toString());
}
catch(IOException e) {
e.printStackTrace();
Log.d("MyPlaces","No data conection avilable");
/* ToDo : put something useful here */
}
// If the address loader returns some results
if (suggested.size() > 0) {
filterResults.values = suggested;
filterResults.count = suggested.size();
// If there are no result with the given input we check last input and result.
// If the new input is more accurate than the previous, display result for the
// previous one.
} else if (constraint.toString().contains(lastInput)) {
debug = true;
Log.d("MyPlaces","Keep last suggestion : " + lastSuggested.get(0).toString());
filterResults.values = lastSuggested;
filterResults.count = lastSuggested.size();
} else {
filterResults.values = new ArrayList<Address>();
filterResults.count = 0;
}

if ( filterResults.count > 0) {
lastSuggested = (ArrayList<Address>) filterResults.values;
}
lastInput = constraint.toString();
}
if (debug) {
Log.d("MyPlaces","filter result count :" + filterResults.count);
}
return filterResults;
}

@Override
protected void publishResults(CharSequence contraint, FilterResults results) {
AddressAutoCompleteAdapter.this.notifyDataSetChanged();
}
};
return myFilter;
}

...

AddressLoader(部分代码已被删除)

public class GeocoderAddressLoader implements AddressLoader {

private Application app;
private int maxSuggestionsCount;
private LocationManager locationManager;

@Inject
public GeocoderAddressLoader(
Application app,
LocationManager locationManager,
@Assisted int maxSuggestionsCount){
this.maxSuggestionsCount = maxSuggestionsCount;
this.app = app;
this.locationManager = locationManager;
}

/**
* Take a string representing an address or a place and return a list of corresponding
* addresses
* @param addrString A String representing an address or place
* @return List of Address corresponding to the given address description
* @throws IOException If Geocoder API cannot be called
*/
public ArrayList<Address> load(String addrString) throws IOException {
//Try to filter with the current location
Location current = locationManager.getLastKnownLocation(LocationManager.NETWORK_PROVIDER);
Geocoder geocoder = new Geocoder(app,Locale.getDefault());
ArrayList<Address> local = new ArrayList<Address>();
if (current != null) {
local = (ArrayList<Address>) geocoder.getFromLocationName(
addrString,
maxSuggestionsCount,
current.getLatitude()-0.1,
current.getLongitude()-0.1,
current.getLatitude()+0.1,
current.getLongitude()+0.1);
}
if (local.size() < maxSuggestionsCount) {
ArrayList<Address> global = (ArrayList<Address>) geocoder.getFromLocationName(
addrString, maxSuggestionsCount - local.size());
for (Address globalAddr : global) {
if (!containsAddress(local,globalAddr))
local.add(globalAddr);
}
}
return local;
}

...

问题

这个实现确实有效,但并不完美。

AddressLoader 有一些输入时出现奇怪的行为。
例如如果用户想输入这个地址

10 rue Guy Ropartz 54600 Villers-les-Nancy  

当他进入时:

10 rue Guy

有一些建议,但不是想要的地址。
如果达到此输入时他继续输入文本:

10 rue Guy Ro

建议消失。当输入为时,最终出现所需的地址

10 rue Guy Ropart

我认为这会让用户感到不安。奇怪的是没有建议 "10 rue Guy Ro" 而有建议 "10 rue Guy""10 rue Guy Ropart"嗯>...

一种可能的解决方法

我想出了解决此问题的可能方法并尝试实现它。这个想法是如果在输入更长的地址后没有 AdressLoader 建议的地址,则保留先前的建议。在我们的示例中,当输入为 “10 rue Guy Ro” 时,保留 “10 rue Guy” 建议。

很遗憾,我的代码不起作用。当我处于这种情况时,代码的大部分内容都达到了:

else if (constraint.toString().contains(lastInput)) {
debug = true;
Log.d("MyPlaces","Keep last suggestion : " + lastSuggested.get(0).toString());
filterResults.values = lastSuggested;
filterResults.count = lastSuggested.size();
}

performFiltering 返回的 FilterResult 中充满了好的建议,但它没有出现在 View 中。也许我错过了 publishResults 中的某些内容...

问题

  • 地理编码器有时会出现奇怪的行为,也许有更好的方法来获取地址建议?
  • 你能推荐一个比我描述的更好的解决方法吗?
  • 我的变通方法的实现有什么问题?

更新
出于兼容性考虑,我基于 Google Geocode Http API 实现了一个新的 AddressLoader。 (因为默认的 Android 地理编码器服务并非在所有设备上都可用)。它重现了完全相同的奇怪行为。

最佳答案

Geocoder api 的设计目的不是为“10 rue Guy Ro”等部分字符串提供建议。你可以在谷歌地图上试试这个,输入“10 rue Guy Ro”,留个空格。你不会得到任何建议(谷歌地图使用地理编码器),但是当你删除空间时,你会得到关于部分字符串的建议(谷歌地图使用私有(private) API)。您可以像使用 Google map 一样使用 Geocoder api,仅在用户在他输入的字符串中输入空格后获取建议。

关于Android AutocompleteTextView 使用 ArrayAdapter 和 Filter,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10050108/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com