java 在android中扩展ArrayAdapter

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10379261/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 00:46:07  来源:igfitidea点击:

Extending ArrayAdapter in android

javaandroidandroid-arrayadapterinner-classes

提问by Jeyanth Kumar

I need to override a getFilter()method from the class ArrayAdapterand i found the source code from here in the github

我需要覆盖getFilter()类中的一个方法ArrayAdapter,我在 github 中找到了这里的源代码

//package name

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.content.Context;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.Filter;
import android.widget.Filterable;

public class CustomAdapter<T> extends ArrayAdapter<T> implements Filterable{

    private ArrayList<T> mOriginalValues;
    private List<T> mObjects;
    private CustomFilter mFilter;
    private final Object mLock = new Object();
    public CustomAdapter(Context context, int textViewResourceId, T[] objects) {
        super(context, textViewResourceId, objects);

        mObjects = Arrays.asList(objects);
        // TODO Auto-generated constructor stub
    }

    @Override
    public Filter getFilter() {
        // TODO Auto-generated method stub
        if (mFilter == null) {
            mFilter = new CustomFilter();
        }
        return mFilter;
    }


    private class CustomFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();
            Log.d("bajji", "its ---> " + prefix);
            if (mOriginalValues == null) {
                synchronized (mLock) {
                    mOriginalValues = new ArrayList<T>(mObjects);
                }
            }

            if (prefix == null || prefix.length() == 0) {
                ArrayList<T> list;
                synchronized (mLock) {
                    list = new ArrayList<T>(mOriginalValues);
                }
                results.values = list;
                results.count = list.size();
            } else {
                String prefixString = prefix.toString().toLowerCase();

                ArrayList<T> values;
                synchronized (mLock) {
                    values = new ArrayList<T>(mOriginalValues);
                }

                final int count = values.size();
                final ArrayList<T> newValues = new ArrayList<T>();
                final ArrayList<T> approxValues = new ArrayList<T>();
                final ArrayList<T> secondApproxValues = new ArrayList<T>();


                for (int i = 0; i < count; i++) {
                    final T value = values.get(i);
                    final String valueText = value.toString().toLowerCase();
                    boolean flag = true;
                    // First match against the whole, non-splitted value
                    if (valueText.startsWith(prefixString)) {
                        newValues.add(value);
                        flag = false;
                    } else {
                        final String[] words = valueText.split(" ");
                        final int wordCount = words.length;

                        // Start at index 0, in case valueText starts with space(s)
                        for (int k = 0; k < wordCount; k++) {
                            if (words[k].startsWith(prefixString)) {
                                newValues.add(value);
                                flag = false;
                                break;
                            } 
                        }
                    }

                    if(flag) {
                        if(approxMatch(valueText, prefixString) <= 3) { //change the stuff and do a levi work
                            approxValues.add(value);
                        }
                        else {
                            final String[] words = valueText.split(" ");
                            final int wordCount = words.length;

                            // Start at index 0, in case valueText starts with space(s)
                            for (int k = 0; k < wordCount; k++) {
                                if(approxMatch(words[k], prefixString) <= 3) {
                                    //leve work
                                    secondApproxValues.add(value);
                                    break;
                                }
                            }
                        }
                    }
                }
                newValues.addAll(approxValues);
                newValues.addAll(secondApproxValues);
                results.values = newValues;
                results.count = newValues.size();
            }
            return results;
        }
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            //noinspection unchecked
            mObjects = (List<T>) results.values;
            if (results.count > 0) {
                notifyDataSetChanged();
            } else {
                notifyDataSetInvalidated();
            }
        }
    }

    private int approxMatch (String s, String t) {
          // an approxmimate string matching algo
          return p;
    }
}

The problem is the getFilter method has a object of a private inner class ArrayFilterwhich has a method peformFilteringand i need to put a different code there so i have to overide the class. And i get an exception in the method.

问题是 getFilter 方法有一个私有内部类的对象,ArrayFilter它有一个方法peformFiltering,我需要在那里放一个不同的代码,所以我必须覆盖这个类。我在方法中遇到了异常。

In the derived class which extends ArrayAdapter i created a private inner class which is similar to ArrayFilterand called it MyFilterand i get the same exception again in the method performFiltering.

在扩展 ArrayAdapter 的派生类中,我创建了一个类似于ArrayFilter并调用它的私有内部类,MyFilter我在方法中再次遇到相同的异常performFiltering

I found a solution to solve my problem. I copied all the code in ArrayAdapterclass and created a new class called MyAdapterand i altered some code inside the inner class ArrayFilterand the app works the way i wanted it to. But i feel its not the best solution.

我找到了一个解决方案来解决我的问题。我复制了ArrayAdapter类中的所有代码并创建了一个名为的新类MyAdapter,我更改了内部类中的一些代码ArrayFilter,应用程序按照我想要的方式工作。但我觉得这不是最好的解决方案。

Android has various api levels so if the array adapter is changed in different api level then i have to add those changes in my codes to. So i feel the best way is to extend the class ArrayAdapterto create MyAdapterrather than just copying and pasting the code from the ArrayAdapter

Android 有各种 api 级别,因此如果数组适配器在不同的 api 级别中更改,那么我必须将这些更改添加到我的代码中。所以我觉得最好的方法是扩展类ArrayAdapter来创建MyAdapter而不是仅仅从ArrayAdapter

How can i override the inner private class of a parent class..?

如何覆盖父类的内部私有类..?

Edit: The exception i get.. Exception

编辑:我得到的例外.. 例外

Edit2: Now i added the full code in the question. and it works perfectly if i copy and edit the array adapter.. the problem is only when i extend..!! now the code and search is working perfectly. I checked it with Log.i.. but the drop down list for auto complete suggestion in UI is not working.. i only get for the first character i type the next character filtering takes place but UI update is not taking place.

Edit2:现在我在问题中添加了完整的代码。如果我复制和编辑阵列适配器,它可以完美运行.. 问题仅在我扩展时..!!现在代码和搜索工作正常。我用Log.i..检查过它,但是 UI 中自动完成建议的下拉列表不起作用。

采纳答案by Jeyanth Kumar

After some help from stackoverflow community i removed the exception and later i found out that the suggestions that are returned doesn't really change because the mObjectswas returned from the super class or base class. The problem was the there were two public methods getCount()and getItem(int position)which gets the count and fetches the list from mObjects from the base class. So i just have to add those two methods in my class..

在获得 stackoverflow 社区的一些帮助后,我删除了异常,后来我发现返回的建议并没有真正改变,因为它mObjects是从超类或基类返回的。问题是有两个公共方法getCount()getItem(int position)它们从基类的 mObjects 获取计数和获取列表。所以我只需要在我的班级中添加这两个方法..

public int getCount() {
    return mObjects.size();
}

public T getItem(int position) {
    return mObjects.get(position);
}

Now mObjectsof the derived class will be returned. Which are the updated in the dropdown list in the UI.

现在mObjects将返回派生类。哪些是在 UI 的下拉列表中更新的。

I am not a java expert, but this solves my problem. If you have any suggestions to make the code better please add it in comments or feel free to edit the answer.!

我不是 Java 专家,但这解决了我的问题。如果您有任何改进代码的建议,请在评论中添加或随时编辑答案。!

回答by Ronnie

Update:

更新:

You should override the toString()method in your Tclass and return the filter criterion string.

您应该覆盖类中的toString()方法T并返回过滤条件字符串。

For example,

例如,

class T {

    String firstName;
    String lastName;
    ...
    ...
    @override
    String toString() {
        return firstName + lastName;
    }
}

By default, the toString()implementation of the Objectclass returns getClass().getName() + '@' + Integer.toHexString(hashCode())

默认情况下,类的toString()实现Object返回getClass().getName() + '@' + Integer.toHexString(hashCode())

Original:

原来的:

The array list reference should be passed to the ArrayAdapterconstructor. I think you are not doing this and hence its not able to get a list for filtering.

数组列表引用应该传递给ArrayAdapter构造函数。我认为你没有这样做,因此它无法获得过滤列表。

In this sample code objectsarray reference is passed to the super constructor.

在此示例代码中,objects数组引用被传递给超级构造函数。

public CustomAdapter(Context context, int tvResId, ArrayList<String> objects) {
    super(context, textViewResourceId, objects);
    this.objects = objects;
}

If your filtering is based on the simple strings in the list items, then you can implement TextWatcheras suggested by @Iiorry. But if the filtering is bit complex than that, then you need to implement Filterableas well.

如果您的过滤基于列表项中的简单字符串,那么您可以TextWatcher按照@Iiorry 的建议实施。但如果过滤比这更复杂,那么您也需要实现Filterable

回答by Lior Iluz

You don't need to implement your own filter... just override getFilter as @Waqas suggested.

您不需要实现自己的过滤器...只需按照@Waqas 的建议覆盖 getFilter 即可。

Here's what I did and it works. Feel free to adjust it to your needs...

这就是我所做的并且它有效。随意调整它以满足您的需要......

Hope it'll help.

希望它会有所帮助。

The EditText (searchFilder):

EditText (searchFilder):

searchFilter.addTextChangedListener(mOnSearchBoxTextChanged);
private TextWatcher mOnSearchBoxTextChanged = new TextWatcher() {

        public void afterTextChanged(Editable s) {
        }

        public void beforeTextChanged(CharSequence s, int start, int count,
                int after) {
        }

        public void onTextChanged(CharSequence s, int start, int before,
                int count) {
            mAdapter.getFilter().filter(s.toString());
        }

    };

The Adapter getFilter():

适配器 getFilter():

    class MyAdapter extends BaseAdapter implements Filterable {

            //the rest of the adapter....

            @Override
            public Filter getFilter() {
                if (newFilter == null) {
                    newFilter = new Filter() {
                        @Override
                        protected void publishResults(CharSequence prefix,
                                FilterResults results) {

                            CLog.logD( "Friends list filtered");

                            mAdapter.notifyDataSetChanged();
                        }

                        @Override
                protected FilterResults performFiltering(CharSequence constraint) {
                    constraint = constraint.toString().toLowerCase();

                    filteredFriendList = new ArrayList<FriendsListItemView>();

                    if (constraint!= null && constraint.toString().length() > 0) {
                        for (int i = 0; i < friendsList.size(); i++) {
                            FriendsListItemView newFriend = friendsList.get(i);
                            String name = newFriend.userName.getText().toString();

                            if (name.toLowerCase().contains(constraint)) {
                                filteredFriendList.add(newFriend);
                            } 
                        }

                    } else {
                        if (filteredFriendList.size() == 0) {
                            filteredFriendList = friendsList;
                        }
                    }

                    FilterResults newFilterResults = new FilterResults();
                    newFilterResults.count = filteredFriendList.size();
                    newFilterResults.values = filteredFriendList;
                    return newFilterResults;
                }
            };
                }
                return newFilter;
            }
        }

回答by waqaslam

Perhaps this may help you:

也许这可以帮助你:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import android.content.Context;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.Filter;

public class CustomAdapter<T> extends ArrayAdapter<T> {

    private final ArrayList<T> mOriginalValues;
    private List<T> mObjects;
    private CustomFilter mFilter;
    private final Object mLock = new Object();
    public CustomAdapter(Context context, int textViewResourceId, T[] objects) {
        super(context, textViewResourceId, objects);

        mObjects = Arrays.asList(objects);
        mOriginalValues = (ArrayList<T>) Arrays.asList(objects);
        // TODO Auto-generated constructor stub
    }

    @Override
    public Filter getFilter() {
        // TODO Auto-generated method stub
        if (mFilter == null) {
            mFilter = new CustomFilter();
        }
        return mFilter;
    }


    private class CustomFilter extends Filter {
        @Override
        protected FilterResults performFiltering(CharSequence prefix) {
            FilterResults results = new FilterResults();
            Log.d("bajji", "its ---> " + prefix);

            if (prefix == null || prefix.toString().trim().length() == 0) {
                ArrayList<T> list;
                synchronized (mLock) {
                    list = new ArrayList<T>(mOriginalValues);
                }
                results.values = list;
                results.count = list.size();
            } else {
                String prefixString = prefix.toString().toLowerCase();

                ArrayList<T> values;
                synchronized (mLock) {
                    values = new ArrayList<T>(mOriginalValues);
                }

                final int count = values.size();
                final ArrayList<T> newValues = new ArrayList<T>();
                final ArrayList<T> approxValues = new ArrayList<T>();
                final ArrayList<T> secondApproxValues = new ArrayList<T>();


                for (int i = 0; i < count; i++) {
                    final T value = values.get(i);
                    final String valueText = value.toString().toLowerCase();
                    boolean flag = true;
                    // First match against the whole, non-splitted value
                    if (valueText.startsWith(prefixString)) {
                        newValues.add(value);
                        flag = false;
                    } else {
                        final String[] words = valueText.split(" ");
                        final int wordCount = words.length;

                        // Start at index 0, in case valueText starts with space(s)
                        for (int k = 0; k < wordCount; k++) {
                            if (words[k].startsWith(prefixString)) {
                                newValues.add(value);
                                flag = false;
                                break;
                            } 
                        }
                    }

                    if(flag) {
                        if(approxMatch(valueText, prefixString) <= 3) { //change the stuff and do a levi work
                            approxValues.add(value);
                        }
                        else {
                            final String[] words = valueText.split(" ");
                            final int wordCount = words.length;

                            // Start at index 0, in case valueText starts with space(s)
                            for (int k = 0; k < wordCount; k++) {
                                if(approxMatch(words[k], prefixString) <= 3) {
                                    //leve work
                                    secondApproxValues.add(value);
                                    break;
                                }
                            }
                        }
                    }
                }
                newValues.addAll(approxValues);
                newValues.addAll(secondApproxValues);
                results.values = newValues;
                results.count = newValues.size();
            }
            return results;
        }
        @Override
        protected void publishResults(CharSequence constraint, FilterResults results) {
            //noinspection unchecked
            mObjects = (List<T>) results.values;
            notifyDataSetChanged();
            clear();
            for(T tmp : mObjects){
                add(tmp);
            }

            notifyDataSetChanged();
        }
    }

    private int approxMatch (String s, String t) {
          // an approxmimate string matching algo
          return p;
    }
}

Now in getViewmethod of adapter, you need to refer to mObjectsobject to get recent available values for ListView

现在在getView适配器的方法中,您需要引用mObjects对象以获取 ListView 最近可用的值