Android 中的地理编码器自动完成
我一直在谷歌上搜索试图找到与我有同样问题的人,但没有运气。所以这是我的问题:
当用户使用 Android 中的地理编码器键入地点名称时,我试图实现地址的自动完成建议。我希望它的行为与使用组合框的 javascript 版本大致相同。
我使用带有 AutoCompleteTextView 的布局和数组适配器来根据用户类型动态更新建议列表。我在使用处理程序调用 geocoder.getFromLocationName 之前添加了从收到 onTextChanged() 事件起的 500 毫秒延迟。如果用户在 500 毫秒内输入更多字母,则最后一个事件将被取消。我遇到的问题是,建议几乎从不作为下拉菜单中的可选选项显示在用户界面中。我得到了地址建议,但是当我将它们添加到附加到 autocomplatetextview 的适配器时,它们根本不会显示。
我正在使用 API 级别 7 的模拟器上运行它,其中包含 google api。
现在一些源代码可以帮助您: 布局:
<LinearLayout android:id="@+id/searchInputLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="6dip"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/searchMessage" />
<EditText android:id="@+id/freetextInput"
android:hint="@string/searchFreetextLabel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/editbox_background" />
<CheckBox android:id="@+id/includeVincinityCheckbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/includeVincinityLabel"
android:checked="true"
android:onClick="includeVincinityClick" />
<AutoCompleteTextView android:id="@+id/locationInput"
android:hint="@string/locationInputHint"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button android:id="@+id/searchButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/searchBtnLabel"
android:onClick="searchBtnClicked" />
</LinearLayout>
我的活动的源代码(我省略了不相关的代码):
public class SearchLocationTabActivity extends Activity implements TextWatcher, OnItemSelectedListener {
private static final int MESSAGE_TEXT_CHANGED = 0;
private static final int AUTOCOMPLETE_DELAY = 500;
private static final int THRESHOLD = 3;
private String latitude, longitude;
private List<Address> autoCompleteSuggestionAddresses;
private ArrayAdapter<String> autoCompleteAdapter;
private Handler messageHandler;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.search);
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
messageHandler = new MyMessageHandler(this, this);
autoCompleteAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, new ArrayList<String>());
autoCompleteAdapter.setNotifyOnChange(false);
AutoCompleteTextView locationinput = (AutoCompleteTextView) findViewById(R.id.locationInput);
locationinput.addTextChangedListener(this);
locationinput.setOnItemSelectedListener(this);
locationinput.setThreshold(THRESHOLD);
locationinput.setAdapter(autoCompleteAdapter);
}
@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
messageHandler.removeMessages(MESSAGE_TEXT_CHANGED);
}
@Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
String value = arg0.toString();
if (!"".equals(value) && value.length() >= THRESHOLD) {
Message msg = Message.obtain(messageHandler, MESSAGE_TEXT_CHANGED, arg0.toString());
messageHandler.sendMessageDelayed(msg, AUTOCOMPLETE_DELAY);
} else {
autoCompleteAdapter.clear();
}
}
@Override
public void afterTextChanged(Editable arg0) {
}
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
if (arg2 < autoCompleteSuggestionAddresses.size()) {
Address selected = autoCompleteSuggestionAddresses.get(arg2);
latitude = Double.toString(selected.getLatitude());
longitude = Double.toString(selected.getLongitude());
}
}
private void notifyResult(List<Address> suggestions) {
latitude = longitude = null;
autoCompleteAdapter.clear();
for (Address a : autoCompleteSuggestionAddresses) {
autoCompleteAdapter.add(a.toString());//TODO: figure out a nice way to display this address in list
}
autoCompleteAdapter.notifyDataSetChanged();
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
latitude = longitude = null;
}
private class MyMessageHandler extends Handler {
private Context context;
private AsyncTaskSubscriber subscriber;
public MyMessageHandler(Context context, AsyncTaskSubscriber subscriber) {
this.context = context;
this.subscriber = subscriber;
}
@Override
public void handleMessage(Message msg) {
if (msg.what == MESSAGE_TEXT_CHANGED) {
String enteredText = (String) msg.obj;
try {
autoCompleteSuggestionAddresses = new Geocoder(context).getFromLocationName(enteredText, 10);
notifyResult(response);
} catch (IOException ex) {
Log.e(GeoCoderAsyncTask.class.getName(), "Failed to get autocomplete suggestions", ex);
}
}
}
}
}
非常感谢任何帮助!
I've been googling my ass of trying to find someone that are having the same problem as me, without luck. So here's my problem:
I'm trying to implement a autocomplete suggestion of addresses as the user types the name of a place using the geocoder in Android. I want this to behave much the same as the javascript version using a combbox.
I am using a layout with an AutoCompleteTextView, and an arrayadapter to dynamically update the suggestionlist as the user types. I have added a 500ms delay from when the onTextChanged() event is received before a call to the geocoder.getFromLocationName is called using a Handler. If a user types more letter within 500ms, the last event will be cancelled. The problem I am encountering is that the suggestions almost never show up in the UI as selectables in the dropdown. I get the address suggestions, but when I add them to the adapter attached to the autocomplatetextview they simple wont show.
I'm running this on an emulator using API level 7, with google apis included.
Now some source code to aid you:
The layout:
<LinearLayout android:id="@+id/searchInputLayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="6dip"
android:orientation="vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/searchMessage" />
<EditText android:id="@+id/freetextInput"
android:hint="@string/searchFreetextLabel"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/editbox_background" />
<CheckBox android:id="@+id/includeVincinityCheckbox"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/includeVincinityLabel"
android:checked="true"
android:onClick="includeVincinityClick" />
<AutoCompleteTextView android:id="@+id/locationInput"
android:hint="@string/locationInputHint"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
<Button android:id="@+id/searchButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/searchBtnLabel"
android:onClick="searchBtnClicked" />
</LinearLayout>
The source code of my activity (I've omitted code not relevant):
public class SearchLocationTabActivity extends Activity implements TextWatcher, OnItemSelectedListener {
private static final int MESSAGE_TEXT_CHANGED = 0;
private static final int AUTOCOMPLETE_DELAY = 500;
private static final int THRESHOLD = 3;
private String latitude, longitude;
private List<Address> autoCompleteSuggestionAddresses;
private ArrayAdapter<String> autoCompleteAdapter;
private Handler messageHandler;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
setContentView(R.layout.search);
setDefaultKeyMode(DEFAULT_KEYS_SEARCH_LOCAL);
messageHandler = new MyMessageHandler(this, this);
autoCompleteAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_dropdown_item_1line, new ArrayList<String>());
autoCompleteAdapter.setNotifyOnChange(false);
AutoCompleteTextView locationinput = (AutoCompleteTextView) findViewById(R.id.locationInput);
locationinput.addTextChangedListener(this);
locationinput.setOnItemSelectedListener(this);
locationinput.setThreshold(THRESHOLD);
locationinput.setAdapter(autoCompleteAdapter);
}
@Override
public void beforeTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
messageHandler.removeMessages(MESSAGE_TEXT_CHANGED);
}
@Override
public void onTextChanged(CharSequence arg0, int arg1, int arg2, int arg3) {
String value = arg0.toString();
if (!"".equals(value) && value.length() >= THRESHOLD) {
Message msg = Message.obtain(messageHandler, MESSAGE_TEXT_CHANGED, arg0.toString());
messageHandler.sendMessageDelayed(msg, AUTOCOMPLETE_DELAY);
} else {
autoCompleteAdapter.clear();
}
}
@Override
public void afterTextChanged(Editable arg0) {
}
@Override
public void onItemSelected(AdapterView<?> arg0, View arg1, int arg2, long arg3) {
if (arg2 < autoCompleteSuggestionAddresses.size()) {
Address selected = autoCompleteSuggestionAddresses.get(arg2);
latitude = Double.toString(selected.getLatitude());
longitude = Double.toString(selected.getLongitude());
}
}
private void notifyResult(List<Address> suggestions) {
latitude = longitude = null;
autoCompleteAdapter.clear();
for (Address a : autoCompleteSuggestionAddresses) {
autoCompleteAdapter.add(a.toString());//TODO: figure out a nice way to display this address in list
}
autoCompleteAdapter.notifyDataSetChanged();
}
@Override
public void onNothingSelected(AdapterView<?> arg0) {
latitude = longitude = null;
}
private class MyMessageHandler extends Handler {
private Context context;
private AsyncTaskSubscriber subscriber;
public MyMessageHandler(Context context, AsyncTaskSubscriber subscriber) {
this.context = context;
this.subscriber = subscriber;
}
@Override
public void handleMessage(Message msg) {
if (msg.what == MESSAGE_TEXT_CHANGED) {
String enteredText = (String) msg.obj;
try {
autoCompleteSuggestionAddresses = new Geocoder(context).getFromLocationName(enteredText, 10);
notifyResult(response);
} catch (IOException ex) {
Log.e(GeoCoderAsyncTask.class.getName(), "Failed to get autocomplete suggestions", ex);
}
}
}
}
}
Any help is much appreciated!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
对于那些未能删除过滤的人,这就是我所做的(以及其他小的修改,但我认为它们不会对过滤部分产生影响)。另请注意,要检测要检测的某个项目的点击,您需要添加一个 OnItemClickListener。
ArrayAdapterNoFilter 的灵感来自另一个答案:
For those who did not managed to remove the filtering, here is what I've done (among other small modifications but I don't think they have an impact on the filtering part). Note also that for a click on one of the item to be detected, you need to add an OnItemClickListener.
Where ArrayAdapterNoFilter is inspired from this other answer:
好的,这个有一个非常简单的解决方案。由于 AutoCompleteTExtView 组件中的过滤机制,结果并不总是显示出来。由于地理编码器的所有结果不一定包含输入的字符串,因此它不会显示这些结果。
ok, this one has a really simple solution. The results did not show up all the time because of the filtering mechanism in the AutoCompleteTExtView component. Because all results from the geocoder did not necessarily contain the string typed in, it did not show those results.