我正在使用BaseAdapter在SherlockFragment中填充相当大的ListView(~150首歌曲)并且它正常工作。当我尝试使用SearchView时,应用程序崩溃了。并非总是如此,它会随机发生,有时会在第一次输入文本时发生,有时当我更快地更改搜索文本时。我得到的信息是:
Java.lang.IllegalStateException:适配器的内容已更改,但ListView未收到通知。确保不从后台线程修改适配器的内容,而只是从UI线程修改。
我的片段代码:
public class Songs extends SherlockFragment {
private static final String KEY_CONTENT = "Songs:Content";
static final String KEY_ID = "id";
static final String KEY_NAME = "name";
Tost tost;
ListView list;
ArrayList<HashMap<String, String>> songsList;
DatabaseHandler db;
private String mContent = "???";
SongsAdapter adapter;
SearchView searchView;
public static Songs newInstance(String content) {
Songs fragment = new Songs();
StringBuilder builder = new StringBuilder();
for (int i = 0; i < 20; i++) {
builder.append(content).append(" ");
}
builder.deleteCharAt(builder.length() - 1);
fragment.mContent = builder.toString();
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if ((savedInstanceState != null)
&& savedInstanceState.containsKey(KEY_CONTENT)) {
mContent = savedInstanceState.getString(KEY_CONTENT);
}
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
super.onCreateOptionsMenu(menu, inflater);
inflater.inflate(R.menu.songs_menu, menu);
MenuItem searchItem = menu.findItem(R.id.menu_search);
searchView = (SearchView) searchItem.getActionView();
searchView.setQueryHint("Search ...");
searchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {
@Override
public boolean onQueryTextChange(final String newText) {
if (newText.length() != 0) {
showFilteredItems(newText);
return true;
}
return false;
}
@Override
public boolean onQueryTextSubmit(String query) {
return false;
}
});
searchView.setOnCloseListener(new SearchView.OnCloseListener() {
@Override
public boolean onClose() {
showFilteredItems("");
return false;
}
});
}
private void showFilteredItems( String query ) {
adapter.getFilter().filter(query);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.songs, container, false);
setHasOptionsMenu(true);
db = new DatabaseHandler(getActivity());
songsList = new ArrayList<HashMap<String, String>>();
list = (ListView) v.findViewById(R.id.lvSongs);
List<MSong> song = db.getAllSongs();
for (MSong cn : song) {
HashMap<String, String> map = new HashMap<String, String>();
map.put(KEY_ID, String.valueOf(cn.getID()));
map.put(KEY_NAME, cn.getName());
songsList.add(map);
}
adapter = new SongsAdapter((this), songsList);
list.setAdapter(adapter);
return v;
}
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
getActivity().finish();
return true;
}
return false;
}
@Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(KEY_CONTENT, mContent);
}
}
和BaseAdapter:
public class SongsAdapter extends BaseAdapter implements Filterable {
private SherlockFragment fragment;
private ArrayList<HashMap<String, String>> data;
private static LayoutInflater inflater=null;
public ImageLoader imageLoader;
ArrayList<HashMap<String, String>> mDataShown;
ArrayList<HashMap<String, String>> mAllData;
public SongsAdapter(SherlockFragment frag, ArrayList<HashMap<String, String>> d) {
fragment = frag;
data=d;
inflater = (LayoutInflater)fragment.getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader=new ImageLoader(fragment.getActivity().getApplicationContext());
mDataShown= (ArrayList<HashMap<String, String>>) d;
mAllData = (ArrayList<HashMap<String, String>>) mDataShown.clone();
}
public int getCount() {
return mDataShown.size();
}
public Object getItem(int position) {
return data.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi=convertView;
if(convertView==null)
vi = inflater.inflate(R.layout.songs_row, null);
TextView tvname = (TextView)vi.findViewById(R.id.tvName);
HashMap<String, String> song = new HashMap<String, String>();
song = data.get(position);
tvname.setText(song.get(Songs.KEY_NAME));
return vi;
}
public Filter getFilter() {
Filter nameFilter = new Filter() {
@Override
protected FilterResults performFiltering(CharSequence s) {
if(s != null)
{
ArrayList<HashMap<String, String>> tmpAllData = mAllData;
ArrayList<HashMap<String, String>> tmpDataShown = mDataShown;
tmpDataShown.clear();
for(int i = 0; i < tmpAllData.size(); i++)
{
if(tmpAllData.get(i).get(Songs.KEY_NAME).toLowerCase().startsWith(s.toString().toLowerCase()))
{
tmpDataShown.add(tmpAllData.get(i));
}
}
FilterResults filterResults = new FilterResults();
filterResults.values = tmpDataShown;
filterResults.count = tmpDataShown.size();
return filterResults;
}
else
{
return new FilterResults();
}
}
@Override
protected void publishResults(CharSequence s, FilterResults results) {
if(results != null && results.count > 0)
{
notifyDataSetChanged();
}
}};
return nameFilter;
}
}
有人知道为什么会这样吗?
答案 0 :(得分:0)
两种可能性:
1:使用view.post(Runnable r)
确保在listView
的同一个线程上调用此方法:
private void showFilteredItems( String query ) {
list.post(new Runnable(){
public void run()
{
adapter.getFilter().filter(query);
}
});
}
2:也许您需要致电adapter.notifyDataSetChanged();
private void showFilteredItems( String query ) {
adapter.getFilter().filter(query);
adapter.notifyDataSetChanged();
}