Android的AutocompleteTextView使用ArrayAdapter和过滤器 [英] Android AutocompleteTextView using ArrayAdapter and Filter

查看:192
本文介绍了Android的AutocompleteTextView使用ArrayAdapter和过滤器的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

该应用程序,我目前正在写有地方交易。主要的方法来创建一个地方是输入地址。提供了一个方便的方式来做到这一点是对UX非常重要的。

The app I am currently writing deals with places. The main method to create a place is to enter an address. Providing a convenient way to do it is very important for the UX.

调查该问题的同时,我带着这样的结论做到这一点的最好办法是根据当前位置和用户输入(如在谷歌地图应用程序)带有自动完成的文字区域后。由于此功能遗憾的是没有提供的谷歌地图API,我有我自己来实现它。

After investigating the problem a while I came with the conclusion that the best way to do it is a text area with autocompletion based on the current location and user input (like in the Google Map application). Since this feature is unfortunately not provided by the Google Map API I have to implement it by myself.

要获得地址的建议我使用地理codeR 。这些建议被提供给 AutoCompleteTextView 通过一个自定义的 ArrayAdaptor 通过自定义的过滤器

To get address suggestions I use Geocoder. These suggestions are provided to an AutoCompleteTextView by a custom ArrayAdaptor through a custom Filter.

一个ArrayAdapter(有些code已被删除)

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(约code已被删除)

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;
}

...

问题

此实现执行工作,但并不完美。

Problems

This implementation does work, but isn't perfect.

该AddressLoader有一个奇怪的现象,对某些输入。
例如,如果用户要输入这个地址

The AddressLoader have a strange behavior with some input.
For example if the user want to enter this address

10 rue Guy Ropartz 54600 Villers-les-Nancy  

当他有进入:

10 rue Guy

有一些建议,但没有所需的地址。
如果他继续输入文字时,该输入到达:

there are some suggestions but not the desired address.
If the he continue entering text when this input is reached:

10 rue Guy Ro

建议消失。所需的地址apear终于当输入

suggestions disappear. The desired address apear finally when the input is

10 rue Guy Ropart

我觉得这是令人不安的用户。这是奇怪的,有没有建议对10街盖罗的同时也有对的10街人10街盖伊Ropart ...

I think this is disturbing for the user. it's strange that there is no suggestion for "10 rue Guy Ro" while there are suggestions for "10 rue Guy" and "10 rue Guy Ropart"...

我想一个可能的解决此问题,并试图实现它。这样做是为了保持previous建议,如果输入一个较长的地址后,没有通过AdressLoader建议的地址。在我们的例子里保持的10街人的建议,当输入的10街盖罗的。

I imagine a possible workaround for this issue and try to implement it. The idea is to keep previous suggestion if after typing a longer address there are no address suggested by AdressLoader. In our exemple keep "10 rue Guy" suggestions when the input is "10 rue Guy Ro".

不幸的是我的code不起作用。当我在这种情况下的code中的很大一部分是达到了:

Unfortunately my code doesn't work. When I am in this situation the good portion of code is reached :

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();
            }

和返回的FilterResult performFiltering 充满了很好的建议,但它不会出现在视图中。也许我想念的东西在 publishResults

and the FilterResult returned by performFiltering is filled with the good suggestions but it doesn't appear on the view. Maybe I miss something in publishResults...

  • 地理codeR一直有时奇怪的行为,也许有更好的方法来获得地址的建议?
  • 您能否提供我一个更好的解决方法,一个我描述?
  • 有什么问题,我的解决办法的实施

更新
对于兼容性问题,我实现了一个新的AddressLoader基础上,谷歌地理code HTTP API (因为默认的Andr​​oid地理codeR服务并不适用于所有设备)。它再现完全相同的奇怪的行为。

Update
For compatibility concerns, I implemented a new AddressLoader based on the Google Geocode Http API (because the default Android geocoder service is not available on all devices). It reproduce the exact same strange behavior.

推荐答案

中的地缘codeR API的目的不是给像10街盖罗部分字符串的建议。您可以在谷歌地图试试这个,输入10街盖伊罗,并留下一个空间。你不会得到(谷歌地图使用地理codeR),但是当你去除空间,你会得到(谷歌地图使用私​​有API)的部分字符串的建议的任何建议。 您可以使用地理codeR API相同的方式谷歌地图使用,只有在他输入字符串中的用户输入空间获取建议。

The Geocoder api is not designed to give suggestions on partial strings like "10 rue Guy Ro" . You can try this in Google maps, enter "10 rue Guy Ro" and leave a space. You will not get any suggestions(Google maps is using Geocoder) but when you remove the space you will get suggestions on the partial string (Google Maps is using private API). You can use the Geocoder api the same way Google maps use, fetch the suggestion only after the user input space in the string he is typing.

这篇关于Android的AutocompleteTextView使用ArrayAdapter和过滤器的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆