简而言之,我使用标准 SimpleQueryAdapter 过滤了我的列表视图,但是当我尝试应用我的自定义 SimplyQueryAdapter 实现时,它会因异常而中断,我不知道为什么。
在一个缩减级别,我有一个列出项目的应用程序。我一直在尝试通过用户在相关的 EditView 中输入的内容来实现“动态”过滤这些结果的方法。
出于测试目的,我的代码只是在列表顶部有一个按钮,当我单击该按钮时,它会分配一个 FilterQueryProvider 并提供一个硬编码的约束字符串。这模拟了一个人在文本字段中输入类似“ob”的内容。
问题是当我尝试针对通过我的自定义 SimpleQueryAdapter 填充的列表运行时。每次我单击按钮时,它都会减少列表但显示不正确的项目并且还会引发“ java.lang.IllegalStateException ”。例如,我可能会搜索“ob”——而不是显示“robert”,而是显示“andrew”。目前更令人担忧的是例外情况。
这是完整的例外:
04-15 12:23:25.099: ERROR/2130968577MySimpleCursorAdapter.getView(577): java.lang.IllegalStateException: attempt to re-open an already-closed object: android.database.sqlite.SQLiteQuery (mSql = SELECT _id, idSite, idSiteUser, idUser, siteName, siteType, siteUrlIcon, dateModified, siteStatus FROM site WHERE idUser=14742 ORDER BY siteName DESC)
我怀疑我的 Queryadapter 出现问题的原因是,如果我尝试切换到使用非自定义 SimpleQueryAdapter,它会完美运行。但我确实需要实现一个自定义适配器,因为我正在使用延迟图标加载等。
我正在以这种方式进行过滤,因为我希望它使用 WHERE LIKE ('%blah%') 即包含而不是过滤器来搜索表。我通过这个线程找到了这个想法: FilterQueryProvider, filter and ListView
根据异常,我的光标似乎正在关闭,但我没有在任何地方调用 close,并且适配器应该通过 StartManagingCursor 自动管理。我在数据库连接和游标方面做错了吗?我对 FilterQueryProvider 的使用看起来正确吗?
这是代码。为了简洁而对其进行了重组
这是我的主要 ListActivity:
public class ChannelListContainer extends ListActivity {
Context context;
private MyDBAdapter db;
private int dummyUserId = 14742;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this.getApplicationContext();
setContentView(R.layout.channellist);
/* open database connection */
db = new MyDBAdapter(context);
db.open();
Cursor c = db.fetchAllSites(dummyUserId);
startManagingCursor(c);
String[] from = new String[] {DBAdapter.KEY_SITE_NAME};
int[] to = new int[] {R.id.channel_name};
/// Code using my custom SimpleCursorAdapter (does not work). By swapping between my addapter and the standard cursor adapter i can make it work/not work
MySimpleCursorAdapter channels = new MySimpleCursorAdapter(this, R.layout.list_item, c, from, to);
setListAdapter(channels);
/// Code not using my custom SimpleCursorAdapter (works)
//SimpleCursorAdapter channels = new SimpleCursorAdapter(this, R.layout.list_item, c, from, to);
//setListAdapter(channels);
}
private void filterList(CharSequence _constraint) {
/// Code using my custom SimpleCursorAdapter (does not work)
//final MySimpleCursorAdapter channels = (MySimpleCursorAdapter) getListAdapter();
/// Code not using my custom SimpleCursorAdapter (works)
final SimpleCursorAdapter channels = (SimpleCursorAdapter) getListAdapter();
final Cursor oldCursor = channels.getCursor();
Filter filter;
channels.setFilterQueryProvider(filterQueryProvider);
filter = channels.getFilter();
filter.filter(_constraint, new FilterListener() {
public void onFilterComplete(int count) {
stopManagingCursor(oldCursor);
final Cursor newCursor = channels.getCursor();
startManagingCursor(newCursor);
if (oldCursor != null && !oldCursor.isClosed()) {
oldCursor.close();
}
}
});
}
private FilterQueryProvider filterQueryProvider = new FilterQueryProvider() {
public Cursor runQuery(CharSequence _constraint) {
db = new MyDBAdapter(context);
db.open();
Cursor c = db.fetchAllSitesByName(dummyUserId, (String) _constraint);
return c;
}
};
// filter the list when button called. Demo to filter list to "To Do" item.
public void onClick(View _view) {
filterList("To Do");
}
}
这是我的自定义 SimpleCursorAdapter:
public class MySimpleCursorAdapter extends SimpleCursorAdapter{
String[] from;
Cursor c;
private static LayoutInflater inflater=null;
int INDEX_ROWID = 0;
int INDEX_IDSITE = 1;
int INDEX_IDSITEUSER = 2;
int INDEX_IDUSER = 3;
int INDEX_SITE_NAME = 4;
int INDEX_SITE_TYPE = 5;
int INDEX_SITE_URL_ICON = 6;
int INDEX_DATE_MODIFIED = 7;
public MySimpleCursorAdapter(Activity activity, int layout, Cursor cursor, String[] from, int[] to) {
super(activity.getApplicationContext(), layout, cursor, from, to);
this.from = from;
this.c = cursor;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public static class ViewHolder{
public TextView channel_name;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
try {
ViewHolder holder;
if (this.c.moveToPosition(position)) {
if(convertView==null){
vi = inflater.inflate(R.layout.list_item, null);
holder=new ViewHolder();
holder.channel_name=(TextView)vi.findViewById(R.id.channel_name);
vi.setTag(holder);
}
else {
holder=(ViewHolder)vi.getTag();
}
holder.channel_name.setText(c.getString(INDEX_SITE_NAME));
return vi;
}
} catch (Exception e) {
Log.e(R.string.app_name + "MySimpleCursorAdapter.getView",e.toString());
}
return vi;
}
}
数据库打开:
public MyDBAdapter(Context _context) {
context = _context;
dbHelper = new myDbHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public MyDBAdapter open() throws SQLException {
db = dbHelper.getWritableDatabase();
return this;
}
任何帮助将不胜感激。
谢谢,罗伯