2009-08-26 46 views
2

我一直在处理的这个应用程序有数据库与多兆字节的数据进行筛选。很多活动只是ListViews在数据库中通过各种级别的数据递减,直到我们到达“文档”,这只是从数据库中提取并显示在手机上的HTML。我遇到的问题是,其中一些活动需要能够通过捕获键击并在其中重新运行查询并使用“like%blah%”来搜索数据库。除非用户第一次加载数据和用户首次输入按键时,这种方式可以合理快速地进行。我正在使用ResourceCursorAdapter,我在后台线程中生成游标,但为了做一个listAdapter.changeCursor(),我必须使用Handler将它发布到主UI线程。然后这个特定的调用会冻结UI线程足够长的时间带来可怕的ANR对话框。我很好奇我如何将它完全卸载到后台线程,以便用户界面保持响应,并且我们没有弹出ANR对话框。我最初只是返回一个自定义模型对象的ArrayList并使用ArrayAdapter,但(可以理解)客户指出这是糟糕的内存管理,而且我对性能不满意。我真的想避免一个解决方案,我生成对象的庞大名单,然后做一个listAdapter.notifyDataSetChanged /废弃()Android CursorAdapters,ListViews和后台线程

这里是有问题的代码:

private Runnable filterDrugListRunnable = new Runnable() { 
    public void run() { 
     if (filterLock.tryLock() == false) return; 

     cur = ActivityUtils.getIndexItemCursor(DrugListActivity.this); 

     if (cur == null || forceRefresh == true) { 
      cur = docDb.getItemCursor(selectedIndex.getIndexId(), filter); 
      ActivityUtils.setIndexItemCursor(DrugListActivity.this, cur); 
      forceRefresh = false; 
     } 

     updateHandler.post(new Runnable() { 
      public void run() { 
       listAdapter.changeCursor(cur); 
      } 
     }); 

     filterLock.unlock(); 

     updateHandler.post(hideProgressRunnable); 
     updateHandler.post(updateListRunnable); 
    } 
}; 

回答

1

我发现它很难相信只要listAdapter.changeCursor()会花费足够的时间来产生ANR,假设您在后台线程中创建了Cursor。应该不会有那么多工作需要重新绘制一些列表行。我会仔细检查一下,看看你在Handler中做的工作是否与你想象的一样有限。也许可以考虑使用AsyncTask,这样可以更轻松地将后台工作(doInBackground())与UI上线程后处理(onPostExecute())分开。

您可以尝试直接替换适配器,方法是再次调用setAdapter(),并将新的Cursor包装在新的适配器中。

您可以看看AutoCompleteTextView如何处理这种情况,因为它使用SpinnerAdapter进行动态过滤。也许它的一些技巧可以适用于你的情况。

+0

之前,我添加了changeCursor电话,一切很高兴,并在后台运行。有一次,我添加了这个: updateHandler.post(新的Runnable(){ 公共无效的run(){ listAdapter.changeCursor(现);} }); 一切都变得糟糕。 – MattC 2009-08-27 13:04:48

+0

奇怪的问题:什么是你的代码中的filterLock?你是否可能陷入致命的拥抱或僵局? – CommonsWare 2009-08-27 16:42:30

+0

这只是一个锁,我们曾预料会使用的情况下,用户在第一个查询运行时保持打字状态。 逐步调整CursorAdapter的实际代码,changeCursor调用notifyDataSetChanged(),这是挂起的位置。 – MattC 2009-08-27 16:49:48