数据更新后ViewPager中的java.lang.IllegalStateException

时间:2016-02-08 00:36:29

标签: android rest android-viewpager

在将数据添加到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(),这会引发异常。

2 个答案:

答案 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中显示的异常不包含有关在您自己的代码中何处引发错误的线索。