The application's PagerAdapter changed the adapter's contents without calling notifyDataSetChanged
The application’s PagerAdapter changed the adapter’s contents without calling PagerAdapter#notifyDataSetChanged
今天開發的時候遇到如題所述的異常,找了一下在satckoverflow上看到一個比較靠譜的答案:
After ADT 22 the PagerAdapter has gotten very strict about calling notifyDataSetChanged() before calling getCount(). It evidently keeps track of what it thinks the count should be and if this is not the same as what getCount() returns it throws this exception. So the solution is simply to call notifyDataSetChanged() on the adapter every time the size of the data changes.
在adt22之后,PagerAdapter對于notifyDataSetChanged()和getCount()的執行順序是非常嚴格的,系統跟蹤count的值,如果這個值和getCount返回的值不一致,就會拋出這個異常。所以為了保證getCount總是返回一個正確的值,那么在初始化ViewPager時,應先給Adapter初始化內容后再將該adapter傳給ViewPager,如果不這樣處理,在更新adapter的內容后,應該調用一下adapter的notifyDataSetChanged方法。
在初始化ViewPager時,應先給Adapter初始化內容后再將該adapter傳給ViewPager,如果不這樣處理,在更新adapter的內容后,應該調用一下adapter的notifyDataSetChanged方法,否則在ADT22以上使用會報The application’s PagerAdapter changed the adapter’s contents without calling PagerAdapter#notifyDataSetChanged的異常,具體原因可參考:http://stackoverflow.com/questions/16756131/fragmentstatepageradapter-stopped-working-after-updating-to-adt-22
package com.itheima.zhbj52.base;import java.util.ArrayList;import android.app.Activity; import android.content.Intent; import android.graphics.Color; import android.os.Handler; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v4.view.ViewPager.OnPageChangeListener; import android.text.TextUtils; import android.view.MotionEvent; import android.view.View; import android.view.View.OnTouchListener; import android.view.ViewGroup; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.BaseAdapter; import android.widget.ImageView; import android.widget.ImageView.ScaleType; import android.widget.TextView; import android.widget.Toast;import com.google.gson.Gson; import com.itheima.zhbj52.NewsDetailActivity; import com.itheima.zhbj52.R; import com.itheima.zhbj52.domain.NewsData.NewsTabData; import com.itheima.zhbj52.domain.TabData; import com.itheima.zhbj52.domain.TabData.TabNewsData; import com.itheima.zhbj52.domain.TabData.TopNewsData; import com.itheima.zhbj52.global.GlobalContants; import com.itheima.zhbj52.utils.CacheUtils; import com.itheima.zhbj52.utils.PrefUtils; import com.itheima.zhbj52.utils.bitmap.MyBitmapUtils; import com.itheima.zhbj52.view.RefreshListView; import com.itheima.zhbj52.view.RefreshListView.OnRefreshListener; import com.lidroid.xutils.BitmapUtils; import com.lidroid.xutils.HttpUtils; import com.lidroid.xutils.ViewUtils; import com.lidroid.xutils.exception.HttpException; import com.lidroid.xutils.http.ResponseInfo; import com.lidroid.xutils.http.callback.RequestCallBack; import com.lidroid.xutils.http.client.HttpRequest.HttpMethod; import com.lidroid.xutils.view.annotation.ViewInject; import com.viewpagerindicator.CirclePageIndicator;/*** 頁簽詳情頁* * @author Kevin* */ public class TabDetailPager extends BaseMenuDetailPager implementsOnPageChangeListener {NewsTabData mTabData;private TextView tvText;private String mUrl;private TabData mTabDetailData;@ViewInject(R.id.vp_news)private ViewPager mViewPager;@ViewInject(R.id.tv_title)private TextView tvTitle;// 頭條新聞的標題private ArrayList<TopNewsData> mTopNewsList;// 頭條新聞數據集合@ViewInject(R.id.indicator)private CirclePageIndicator mIndicator;// 頭條新聞位置指示器@ViewInject(R.id.lv_list)private RefreshListView lvList;// 新聞列表private ArrayList<TabNewsData> mNewsList; // 新聞數據集合private NewsAdapter mNewsAdapter;private String mMoreUrl;// 更多頁面的地址private Handler mHandler;public TabDetailPager(Activity activity, NewsTabData newsTabData) {super(activity);mTabData = newsTabData;mUrl = GlobalContants.SERVER_URL + mTabData.url;}@Overridepublic View initViews() {View view = View.inflate(mActivity, R.layout.tab_detail_pager, null);// 加載頭布局View headerView = View.inflate(mActivity, R.layout.list_header_topnews,null);ViewUtils.inject(this, view);ViewUtils.inject(this, headerView);// 將頭條新聞以頭布局的形式加給listviewlvList.addHeaderView(headerView);// 設置下拉刷新監聽lvList.setOnRefreshListener(new OnRefreshListener() {@Overridepublic void onRefresh() {getDataFromServer();}@Overridepublic void onLoadMore() {if (mMoreUrl != null) {getMoreDataFromServer();} else {Toast.makeText(mActivity, "最后一頁了", Toast.LENGTH_SHORT).show();lvList.onRefreshComplete(false);// 收起加載更多的布局}}});lvList.setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> parent, View view,int position, long id) {System.out.println("被點擊:" + position);// 35311,34221,34234,34342// 在本地記錄已讀狀態String ids = PrefUtils.getString(mActivity, "read_ids", "");String readId = mNewsList.get(position).id;if (!ids.contains(readId)) {ids = ids + readId + ",";PrefUtils.setString(mActivity, "read_ids", ids);}// mNewsAdapter.notifyDataSetChanged();changeReadState(view);// 實現局部界面刷新, 這個view就是被點擊的item布局對象// 跳轉新聞詳情頁Intent intent = new Intent();intent.setClass(mActivity, NewsDetailActivity.class);intent.putExtra("url", mNewsList.get(position).url);mActivity.startActivity(intent);}});return view;}/*** 改變已讀新聞的顏色*/private void changeReadState(View view) {TextView tvTitle = (TextView) view.findViewById(R.id.tv_title);tvTitle.setTextColor(Color.GRAY);}@Overridepublic void initData() {String cache = CacheUtils.getCache(mUrl, mActivity);if (!TextUtils.isEmpty(cache)) {parseData(cache, false);}getDataFromServer();}private void getDataFromServer() {HttpUtils utils = new HttpUtils();utils.send(HttpMethod.GET, mUrl, new RequestCallBack<String>() {@Overridepublic void onSuccess(ResponseInfo<String> responseInfo) {String result = (String) responseInfo.result;System.out.println("頁簽詳情頁返回結果:" + result);parseData(result, false);lvList.onRefreshComplete(true);// 設置緩存CacheUtils.setCache(mUrl, result, mActivity);}@Overridepublic void onFailure(HttpException error, String msg) {Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();error.printStackTrace();lvList.onRefreshComplete(false);}});}/*** 加載下一頁數據*/private void getMoreDataFromServer() {HttpUtils utils = new HttpUtils();utils.send(HttpMethod.GET, mMoreUrl, new RequestCallBack<String>() {@Overridepublic void onSuccess(ResponseInfo<String> responseInfo) {String result = (String) responseInfo.result;parseData(result, true);lvList.onRefreshComplete(true);}@Overridepublic void onFailure(HttpException error, String msg) {Toast.makeText(mActivity, msg, Toast.LENGTH_SHORT).show();error.printStackTrace();lvList.onRefreshComplete(false);}});}protected void parseData(String result, boolean isMore) {Gson gson = new Gson();mTabDetailData = gson.fromJson(result, TabData.class);System.out.println("頁簽詳情解析:" + mTabDetailData);// 處理下一頁鏈接String more = mTabDetailData.data.more;if (!TextUtils.isEmpty(more)) {mMoreUrl = GlobalContants.SERVER_URL + more;} else {mMoreUrl = null;}if (!isMore) {mTopNewsList = mTabDetailData.data.topnews;mNewsList = mTabDetailData.data.news;if (mTopNewsList != null) {mViewPager.setAdapter(new TopNewsAdapter());mIndicator.setViewPager(mViewPager);mIndicator.setSnap(true);// 支持快照顯示mIndicator.setOnPageChangeListener(this);mIndicator.onPageSelected(0);// 讓指示器重新定位到第一個點tvTitle.setText(mTopNewsList.get(0).title);}if (mNewsList != null) {mNewsAdapter = new NewsAdapter();lvList.setAdapter(mNewsAdapter);}// 自動輪播條顯示if (mHandler == null) {mHandler = new Handler() {public void handleMessage(android.os.Message msg) {int currentItem = mViewPager.getCurrentItem();if (currentItem < mTopNewsList.size() - 1) {currentItem++;} else {currentItem = 0;}mViewPager.setCurrentItem(currentItem);// 切換到下一個頁面mHandler.sendEmptyMessageDelayed(0, 3000);// 繼續延時3秒發消息,// 形成循環};};mHandler.sendEmptyMessageDelayed(0, 3000);// 延時3秒后發消息}} else {// 如果是加載下一頁,需要將數據追加給原來的集合ArrayList<TabNewsData> news = mTabDetailData.data.news;mNewsList.addAll(news);mNewsAdapter.notifyDataSetChanged();}}/*** 頭條新聞適配器* * @author Kevin* */class TopNewsAdapter extends PagerAdapter {private BitmapUtils utils;public TopNewsAdapter() {utils = new BitmapUtils(mActivity);utils.configDefaultLoadingImage(R.drawable.topnews_item_default);// 設置默認圖片}@Overridepublic int getCount() {return mTabDetailData.data.topnews.size();//修改為mTopNewsList.size();}@Overridepublic boolean isViewFromObject(View arg0, Object arg1) {return arg0 == arg1;}@Overridepublic Object instantiateItem(ViewGroup container, int position) {ImageView image = new ImageView(mActivity);image.setScaleType(ScaleType.FIT_XY);// 基于控件大小填充圖片TopNewsData topNewsData = mTopNewsList.get(position);utils.display(image, topNewsData.topimage);// 傳遞imagView對象和圖片地址container.addView(image);image.setOnTouchListener(new TopNewsTouchListener());// 設置觸摸監聽return image;}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {container.removeView((View) object);}}/*** 頭條新聞的觸摸監聽* * @author Kevin* */class TopNewsTouchListener implements OnTouchListener {@Overridepublic boolean onTouch(View v, MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:System.out.println("按下");mHandler.removeCallbacksAndMessages(null);// 刪除Handler中的所有消息// mHandler.postDelayed(new Runnable() {//// @Override// public void run() {//// }// }, 3000);break;case MotionEvent.ACTION_CANCEL:System.out.println("事件取消");mHandler.sendEmptyMessageDelayed(0, 3000);break;case MotionEvent.ACTION_UP:System.out.println("抬起");mHandler.sendEmptyMessageDelayed(0, 3000);break;default:break;}return true;}}/*** 新聞列表的適配器* * @author Kevin* */class NewsAdapter extends BaseAdapter {private BitmapUtils utils;// private MyBitmapUtils utils;public NewsAdapter() {utils = new BitmapUtils(mActivity);utils.configDefaultLoadingImage(R.drawable.pic_item_list_default);// utils = new MyBitmapUtils();}@Overridepublic int getCount() {return mNewsList.size();}@Overridepublic TabNewsData getItem(int position) {return mNewsList.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {ViewHolder holder;if (convertView == null) {convertView = View.inflate(mActivity, R.layout.list_news_item,null);holder = new ViewHolder();holder.ivPic = (ImageView) convertView.findViewById(R.id.iv_pic);holder.tvTitle = (TextView) convertView.findViewById(R.id.tv_title);holder.tvDate = (TextView) convertView.findViewById(R.id.tv_date);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}TabNewsData item = getItem(position);holder.tvTitle.setText(item.title);holder.tvDate.setText(item.pubdate);utils.display(holder.ivPic, item.listimage);String ids = PrefUtils.getString(mActivity, "read_ids", "");if (ids.contains(getItem(position).id)) {holder.tvTitle.setTextColor(Color.GRAY);} else {holder.tvTitle.setTextColor(Color.BLACK);}return convertView;}}static class ViewHolder {public TextView tvTitle;public TextView tvDate;public ImageView ivPic;}@Overridepublic void onPageScrollStateChanged(int arg0) {}@Overridepublic void onPageScrolled(int arg0, float arg1, int arg2) {}@Overridepublic void onPageSelected(int arg0) {TopNewsData topNewsData = mTopNewsList.get(arg0);tvTitle.setText(topNewsData.title);} }原因:在加載下一頁的時候,mTabDetailData.data.topnews.size()會發生變化,即PagerAdapter的getCount()會發生變化;解決辦法:在數據發生變化的時候調用PagerAdapter#notifyDataSetChanged()
TopNewsAdapter mTopNewsAdapter; ... mViewPager.setAdapter(new TopNewsAdapter()); mIndicator.setViewPager(mViewPager); ... ArrayList<TabNewsData> news = mTabDetailData.data.news; mNewsList.addAll(news); mNewsAdapter.notifyDataSetChanged(); 《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀總結
以上是生活随笔為你收集整理的The application's PagerAdapter changed the adapter's contents without calling notifyDataSetChanged的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Android下的Linux
- 下一篇: 2017年伊始,你需要尝试的25个And