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
Extending ArrayAdapter in android
提问by Jeyanth Kumar
I need to override a getFilter()
method from the class ArrayAdapter
and 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 ArrayFilter
which has a method peformFiltering
and 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 ArrayFilter
and called it MyFilter
and 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 ArrayAdapter
class and created a new class called MyAdapter
and i altered some code inside the inner class ArrayFilter
and 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 ArrayAdapter
to create MyAdapter
rather 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..
编辑:我得到的例外..
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 mObjects
was 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 mObjects
of 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 T
class 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 Object
class returns getClass().getName() + '@' + Integer.toHexString(hashCode())
默认情况下,类的toString()
实现Object
返回getClass().getName() + '@' + Integer.toHexString(hashCode())
Original:
原来的:
The array list reference should be passed to the ArrayAdapter
constructor. I think you are not doing this and hence its not able to get a list for filtering.
数组列表引用应该传递给ArrayAdapter
构造函数。我认为你没有这样做,因此它无法获得过滤列表。
In this sample code objects
array 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 TextWatcher
as suggested by @Iiorry. But if the filtering is bit complex than that, then you need to implement Filterable
as 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 getView
method of adapter, you need to refer to mObjectsobject to get recent available values for ListView
现在在getView
适配器的方法中,您需要引用mObjects对象以获取 ListView 最近可用的值