ListView在SearchView上崩溃

时间:2013-09-15 10:53:14

标签: android listview baseadapter searchview

我正在使用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;
       }


}

有人知道为什么会这样吗?

1 个答案:

答案 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();
}