a.b*_*b.d 25 android autocomplete autocompletetextview android-arrayadapter
我目前正在撰写的应用程序处理地点.创建场所的主要方法是输入地址.提供便捷的方法对于UX来说非常重要.
在调查问题一段时间后,我得出的结论是,最好的方法是根据当前位置和用户输入自动完成的文本区域(如Google Map应用程序中).由于Google Map API不提供此功能,因此我必须自行实施.
为了获得地址建议我使用Geocoder.这些建议由自定义ArrayAdaptor通过自定义过滤器提供给AutoCompleteTextView.
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;
}
...
Run Code Online (Sandbox Code Playgroud)
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;
}
...
Run Code Online (Sandbox Code Playgroud)
这种实现确实有效,但并不完美.
AddressLoader有一些输入的奇怪行为.
例如,如果用户想要输入此地址
10 rue Guy Ropartz 54600 Villers-les-Nancy
Run Code Online (Sandbox Code Playgroud)
当他进入:
10 rue Guy
Run Code Online (Sandbox Code Playgroud)
有一些建议,但不是所需的地址.
如果他在达到此输入时继续输入文本:
10 rue Guy Ro
Run Code Online (Sandbox Code Playgroud)
建议消失了.输入的最终所需地址
10 rue Guy Ropart
Run Code Online (Sandbox Code Playgroud)
我认为这对用户来说是令人不安的.奇怪的是,没有关于"10 rue Guy Ro"的建议,而有"10 rue Guy"和"10 rue Guy Ropart"的建议 ......
我想象一下这个问题可能的解决方法并尝试实现它.如果在输入更长的地址后没有AdressLoader建议的地址,那么我们的想法是保留先前的建议.在我们的例子中保留"10 rue Guy"的建议,当输入是"10 rue Guy Ro"时.
不幸的是我的代码不起作用.当我处于这种情况时,达到了良好的代码部分:
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();
}
Run Code Online (Sandbox Code Playgroud)
并且performFiltering返回的FilterResult 充满了好的建议,但它没有出现在视图上.也许我想念publishResults中的一些东西...
更新
为了兼容性问题,我实施了一个基于Google Geocode Http API的新AddressLoader (因为默认的Android地理编码器服务并非在所有设备上都可用).它重现了完全相同的奇怪行为.
尝试改变这部分代码:
if ( filterResults.count > 0) {
lastSuggested = (ArrayList<Address>) filterResults.values;
}
lastInput = constraint.toString();
Run Code Online (Sandbox Code Playgroud)
进入这个:
if ( filterResults.count > 0) {
lastSuggested = (ArrayList<Address>) filterResults.values;
lastInput = constraint.toString();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7849 次 |
| 最近记录: |