在将数据添加到viewPager
时会出现异常02-07 19:21:24.488 5577-5577 / com.jamesb.encoderyapp E / AndroidRuntime:FATAL EXCEPTION:main 过程:com.jamesb.encoderyapp,PID:5577 java.lang.IllegalStateException:应用程序的PagerAdapter在不调用PagerAdapter#notifyDataSetChanged的情况下更改了适配器的内容!预期的适配器项目数:4,找到:8寻呼机ID:com.jamesb.encoderyapp:id / pager寻呼机类:类android.support.v4.view.ViewPager有问题的适配器:类com.jamesb.encoderyapp.adapters.ViewPagerAdapter 在android.support.v4.view.ViewPager.populate(ViewPager.java:1000) 在android.support.v4.view.ViewPager.populate(ViewPager.java:952) 在android.support.v4.view.ViewPager $ 3.run(ViewPager.java:251) 在android.view.Choreographer $ CallbackRecord.run(Choreographer.java:767) 在android.view.Choreographer.doCallbacks(Choreographer.java:580) 在android.view.Choreographer.doFrame(Choreographer.java:549) 在android.view.Choreographer $ FrameDisplayEventReceiver.run(Choreographer.java:753) 在android.os.Handler.handleCallback(Handler.java:739) 在android.os.Handler.dispatchMessage(Handler.java:95) 在android.os.Looper.loop(Looper.java:135) 在android.app.ActivityThread.main(ActivityThread.java:5254) at java.lang.reflect.Method.invoke(Native Method) 在java.lang.reflect.Method.invoke(Method.java:372) 在com.android.internal.os.ZygoteInit $ MethodAndArgsCaller.run(ZygoteInit.java:903) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
我从API - 3图片中获取数据,当这些图片被刷过时,我再次调用getContent()方法,此时我得到IllegalStateException。
try {
RestClient.getInstance(getActivity()).getContent(date, new Callback() {
@Override
public void onFailure(Request request, IOException e) {
e.printStackTrace();
}
@Override
public void onResponse(Response response) throws IOException {
String json = response.body().string();
GsonBuilder gsonBuilder = new GsonBuilder();
mGson = gsonBuilder.create();
jsonParsed = mGson.fromJson(json, JsonParsed.class);
if (jsonParsed != null) mApodData.add(jsonParsed);
if (count < iteration) {
count++;
getContent();
} else {
new Handler(Looper.getMainLooper()).post(new Runnable() {
@Override
public void run() {
mAdapter = new ViewPagerAdapter(getActivity(), mApodData);
mViewPager.setAdapter(mAdapter);
mAdapter.notifyDataSetChanged();
}
});
}
}
});
} catch (Exception e) {
e.printStackTrace();
}
查看寻呼机适配器
public class ViewPagerAdapter extends PagerAdapter {
private Activity mActivity;
private ArrayList<JsonParsed> mApodData = new ArrayList<>();
private Utils mUtils;
public ViewPagerAdapter(Activity activity, ArrayList<JsonParsed> mApodData) {
this.mActivity = activity;
this.mApodData = mApodData;
mUtils = new Utils();
}
@Override
public int getCount() {
return mApodData.size();
}
@Override
public int getItemPosition(Object object) {
return POSITION_UNCHANGED;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public View instantiateItem(final ViewGroup container, final int position) {
LayoutInflater inflater = (LayoutInflater) mActivity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
final View itemView = inflater.inflate(R.layout.item, container, false);
final ViewHolder viewHolder = new ViewHolder();
viewHolder.mPic = (ImageView) itemView.findViewById(R.id.picture);
viewHolder.mPicTitle = (TextView) itemView.findViewById(R.id.picTitle);
viewHolder.mDescription = (TextView) itemView.findViewById(R.id.description);
itemView.setTag(viewHolder);
JsonParsed item = mApodData.get(position);
String descr = item.explanation;
String title = item.title;
String picUrl = item.hdurl;
viewHolder.mPicTitle.setText(title);
viewHolder.mDescription.setText(descr);
Picasso.with(mActivity)
.load(String.valueOf(picUrl))
.into(viewHolder.mPic);
viewHolder.mPic.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mUtils.setImageAsWallpaper(mActivity, viewHolder.mPic);
}
});
container.addView(itemView);
return itemView;
}
@Override
public void destroyItem(ViewGroup collection, int position, Object view) {
((ViewPager) collection).removeView((View) view);
}
static class ViewHolder {
ImageView mPic;
TextView mPicTitle;
TextView mDescription;
}
}
我在google中看到过类似的问题,但我不明白我在哪里没有使用notifyDataSetChanged()
,这会引发异常。
答案 0 :(得分:3)
看起来您的适配器正在与您的activity / fragment共享列表引用。这意味着:当这一行执行时
class B
适配器中的列表立即更新 ,因为它基本上是相同的列表。
当 if (jsonParsed != null) mApodData.add(jsonParsed);
正在做它的事情时,它会一次又一次地引用适配器。因此它检查ViewPager
并且适配器没有改变以保持内部一致。
解决此问题的最佳方法是什么?如果您知道最终会有多少页面,请使用getCount()
方法返回该数字。您可以做的另一件事是让适配器创建自己的列表,并在活动列表中执行getCount()
。您还可以在从服务器检索数据时将mList.addAll()
适配器设置为null。
答案 1 :(得分:0)
有人会跳入以下问题,因此我将其发布为一个可能的答案。使ViewPager完美工作确实是一个巨大的时间浪费。 developer.android.com上的(缺失)教程和FragmentPagerAdapter中的代码都是可耻的。世界各地的所有程序员都在努力寻找通向ViewPager正常运行的狭窄之路!
我发现了一个原因,导致您的logcat中出现非法状态,这是由于对.destroyItem()的覆盖而产生的,如下所示:如果您有许多固定的片段,例如开始显示位置0处的片段,例如设置
viewPager.setOffscreenPageLimit (2);
然后,如果用户在以下位置选择了新标签: 4,位置0的片段将被破坏。
在这种情况下,必须调用notifyDataSetChanged(),因为对super的调用(请参见下文)不会将基本FragmentPagerAdapter与其扩展名同步。因此,logcat神秘地说道(在我的案例中有7个片段):
“预期的适配器项数:7,找到的:6寻呼机ID:com.hdsl.a.zapp:id / viewpager寻呼机类:类android.support.v4.view.ViewPager有问题的适配器:”
解释是:我对基类的扩展具有正确的计数(6),而基类则没有(7)。人们应该期望对super的调用能够解决此问题,并且应该,但是不能。以下是纠正此错误的正确代码:
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
super.destroyItem(container, position, object);//Note: does not help to move this to the end of the method
registeredFragmentsList.remove(position);
notifyDataSetChanged();
}
对android核心团队:致电super应该更聪明!虽然不是这种情况,但请使用以下更好的方法增强logcat,例如:“适配器发现FragmentPagerAdapter与扩展类之间的片段数不一致。请确保始终在更改时始终调用.notifyDataSetChanged()。被添加到您的片段列表中。候选者为:(destroyItem,…..)“
“问题适配器”无非是按下狂野猜测按钮。没有帮助。特别是在这种情况下,因为logcat中显示的异常不包含有关在您自己的代码中何处引发错误的线索。