您的位置:首页 > 编程语言 > Java开发

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

2016-01-29 15:26 519 查看
         在手机的某一个界面,是从服务端获取最新的数据,当点击了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 线程

代码改成如下:

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 通知