[置顶] java.lang.IllegalStateException: The content of the adapter has changed but ListView did not receive

         在手机的某一个界面,是从服务端获取最新的数据,当点击了listview的某一项时,跳转到详情页进行显示,点击确认或者取消,返回到主界面时,这个错误有时候就莫名其妙的出现:

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 线程


1
2
3
4
5
6
7
8
9
FusionField.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>}

成功解决,不过上述的一开始的方法也是正确的,欢迎指教。

你可能感兴趣的:(android,通知)