java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive a notification. Make sure the content of your adapter is not modified from a background thread, but only from the UI thread. Make sure your adapter calls notifyDataSetChanged() when its content changes.
原因已经说得很明确了,就是数据更新时,没有及时的更新ui,之前的界面代码是这样的:package client.verbank.mtp.allone.frame.price.pricewarning; import java.util.ArrayList; 。。。。。。。。。。。 public class PriceWarningFragment extends ControlFragment { private Handler handler = new Handler(); private ActionSlideExpandableListView list; // 加载字体 private Typeface facemsyh; private Typeface faceroman; public PriceWarningFragment(MainActivity activity) { super(activity); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { vi = inflater.inflate(R.layout.activity_tipsprice, container, false); // 初始化控件和加载字体 initType(); // 初始化适配器 initAdapter(vi); // 首次加载消息数据 loadTableData();// 初始化消息 // 增加下拉刷新功能 pullRefreshInit(); return vi; } private void initType() { facemsyh = TypeFaceManager.createTypefaceFactory().createMsyh( getSelfActivity()); faceroman = TypeFaceManager.createTypefaceFactory() .createLTS_Roman_Typeface(getSelfActivity()); } // 注册下拉刷新组件监听,初始化 private void pullRefreshInit() { refreshprice_view = (RefreshableView) vi .findViewById(R.id.refreshprice_view); refreshprice_view.setOnRefreshListener(new PullToRefreshListener() { @Override public void onRefresh() { try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } new Thread() { public void run() { try { maps.clear(); queryData(); } finally { handler.post(new Runnable() { @Override public void run() { adapter.notifyDataSetChanged(); refreshprice_view.finishRefreshing(); } }); } } }.start(); } }, 0); } // 初始化适配器 private void initAdapter(View vi) { list = (ActionSlideExpandableListView) vi .findViewById(R.id.listtipsprice); adapter = new TipsPriceAdapter(this); list.setAdapter(adapter); list.setItemActionListener( new ActionSlideExpandableListView.OnActionClickListener() { @Override public void onClick(View listView, View buttonview, int position) { if (maps.isEmpty()) { 。。。。。。。。。。。。。。 } // 初始化加载控件 private ProgressDialog getProgress() { if (progressDialog == null) { progressDialog = DialogManager.showProgressDialog( this.getSelfActivity(), "", getSelfActivity().getString( R.string.pricewarningfragment_datadownload), DialogType.PriceWarning); } return progressDialog; } <span style="color:#ff0000;">// 首次加載頁面,初始化数据,更新界面 private void loadTableData() { Runnable work = new Runnable() { @Override public void run() { getProgress().show(); } }; handler.post(work); new Thread() { @Override public void run() { try { queryData(); } finally { Runnable work = new Runnable() { @Override public void run() { adapter.notifyDataSetChanged(); getProgress().dismiss(); } }; handler.post(work); } } }.start(); }</span> // 通知适配器更新 public void queryData() { if (adapter == null) { return; } refreshListViewDataMap(); } private List<HashMap<String, Object>> refreshListViewDataMap() { maps.clear(); PriceWarning[] pricearray = TradeAPI.getInstance().queryPriceWarning(); if (pricearray != null) { for (PriceWarning priceWarning : pricearray) { HashMap<String, Object> listItem = new HashMap<String, Object>(); String time = TimeUtil.formatTime(priceWarning.getExpiryTime()); if (priceWarning.getIsPriceReach() == CommDataInterface.FALSE && priceWarning.getAccount() == ClientAPI .getAccountId()) { int expire = priceWarning.getExpiryType(); listItem.put("effectivetype", expire); listItem.put("effectivetime", time); listItem.put("instrument", priceWarning.getInstrument()); listItem.put("priceType", priceWarning.getPriceType()); listItem.put("amount", priceWarning.getPrice()); listItem.put("guid", priceWarning.getGuid()); listItem.put("isPriceReach", priceWarning.getIsPriceReach()); maps.add(listItem); } } } return maps; } // 开仓单适配器 public class TipsPriceAdapter extends BaseAdapter { public TipsPriceAdapter(Context myContext) { } public TipsPriceAdapter(PriceWarningFragment tipsPriceFragment) { } @Override public int getCount() { if (maps == null) { return 0; } return maps.size(); } @Override public Object getItem(int position) { return position; } @Override public long getItemId(int position) { return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { ViewHolder viewHolder = null; if (convertView == null) { viewHolder = new ViewHolder(); convertView = getActivity().getLayoutInflater().inflate( R.layout.activity_tipsprice_item, null); ent_middle)); } viewHolder.amount.setText(maps.get(position).get("amount") .toString()); return convertView; } private class ViewHolder { TextView effectivetype; TextView effectivetime; } } <span style="color:#ff0000;">@Override public void onHiddenChanged(boolean hidd) { if (!hidd) { if (getActivity() != null) { loadTableData(); } } }</span> }出错的地方便是在红色的部分,后面使用如下方式进行ui的更新,放弃使用hander类来更新界面:利用Activity.runOnUiThread(Runnable)把更新ui的代码创建在Runnable中,然后在需要更新 ui时,把这个Runnable对象传给Activity.runOnUiThread(Runnable)。 这样Runnable对像就能在ui程序中被调用。如果当前线程是UI线程,那么行动是立即执行。如果当前线程不是UI线程,操作是发布到事件队列的UI 线程
代码改成如下:
123456789FusionField.currentActivity.runOnUiThread(
new
Runnable()
{
public void run()
{
Toast.makeText(getApplicationContext(), ,
"Update My UI"
,
Toast.LENGTH_LONG).show();
}
});
private void updateDataAsync() { new Thread(new Runnable() { @Override public void run() { mapscopy.clear(); PriceWarning[] pricearray = TradeAPI.getInstance() .queryPriceWarning(); if (pricearray != null) { for (PriceWarning priceWarning : pricearray) { HashMap<String, Object> listItem = new HashMap<String, Object>(); String time = TimeUtil.formatTime(priceWarning .getExpiryTime()); if (priceWarning.getIsPriceReach() == CommDataInterface.FALSE && priceWarning.getAccount() == ClientAPI .getAccountId()) { int expire = priceWarning.getExpiryType(); listItem.put("effectivetype", expire); listItem.put("effectivetime", time); listItem.put("instrument", priceWarning.getInstrument()); listItem.put("priceType", priceWarning.getPriceType()); listItem.put("amount", priceWarning.getPrice()); listItem.put("guid", priceWarning.getGuid()); listItem.put("isPriceReach", priceWarning.getIsPriceReach()); mapscopy.add(listItem); } } } // Update your adapter. getActivity().runOnUiThread(new Runnable() { @Override public void run() { maps.clear(); maps.addAll(mapscopy); adapter.notifyDataSetChanged(); list.invalidateViews(); } }); } }).start(); }
这样之后,就解决了这个问题,这个问题已经困扰了好几个月了,终于解决了,因为保密需要,很多多余的代码都已经删掉了。
=======================分割线,2016年3月23日17:16:07:另一种解决方式===================
之后在开发的过程中莫名其妙的又出现了这样的错误,出错的代码如下:
// 初始化maps数据,绑定的适配器的数据源 initCloseHisMapData(result); // 对maps的数据,按照时间进行排序 sortOrderHisByTime(); Runnable work = new Runnable() { @Override public void run() { closeHisAd.notifyDataSetChanged(); } }; getHandler().post(work);
看了这篇博文:http://blog.csdn.net/changemyself/article/details/8116670,才发现数据的获取和通知更新,要放在同一个线程里面,就是说不要分开写,最后是立即更新,修改代码如下:Runnable work = new Runnable() { @Override public void run() { // 初始化maps数据,绑定的适配器的数据源 initCloseHisMapData(result); // 对maps的数据,按照时间进行排序 sortOrderHisByTime(); closeHisAd.notifyDataSetChanged(); } }; getHandler().post(work);</pre><pre code_snippet_id="1569657" snippet_file_name="blog_20160323_5_4073088" name="code" class="java">// 保证金查询适配器 <span style="white-space:pre"> </span>public class MarginDetailAdapter extends BaseAdapter { <span style="white-space:pre"> </span>public MarginDetailAdapter(MarginDetailFragment margindetailFragment) { <span style="white-space:pre"> </span>} <span style="white-space:pre"> </span>@Override <span style="white-space:pre"> </span>public int getCount() { <span style="white-space:pre"> </span>return rowSize; <span style="white-space:pre"> </span>}
成功解决,不过上述的一开始的方法也是正确的,欢迎指教。