IllegalArgumentException:在 ViewPager 中找不到片段 id 的视图 --- ViewPager

2024-02-23

我遇到了困扰我好几天的问题。

有一个ViewPager在主要活动中持有 3Fragments 作为选项卡片段。在里面first片段有一个ListView哪个持有一些观点,哪个是最重要的,另一个ViewPager。我想在子里保留一些照片ViewPager,并在此处使用更多片段。

现在麻烦来了:
当。。。的时候first Fragment已停止(third父级中的片段ViewPager在屏幕上看到)并恢复(用户切换到second片段),应用程序崩溃并且调试器显示:

java.lang.IllegalArgumentException: No view found for id 0x7f05008b (com.example.viewpager:id/sub_viewpager) for fragment ScreenSlidePageFragment

我已经使用过getChildFragmentManager()因为这是一种情况嵌套片段 http://developer.android.com/about/versions/android-4.2.html#NestedFragments.

下面是父ViewPager中第一个fragment对应的列表适配器的关键代码:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    int type = getItemViewType(position);
    switch (type) {
        case TYPE_BANNER:
            if (convertView == null) {
                convertView = mBannerView.getBannerView(parent);
            }
            mBannerView.update(convertView);
            break;
        case TYPE_ITEM:
            break;
    }
    return convertView;
}

这是代码mBannerView:

public class BannerView {

    private static final DisplayImageOptions IMAGE_OPTIONS_SCALE_STRETCHED =
            new DisplayImageOptions.Builder()
                    .cacheInMemory()
                    .cacheOnDisc()
                    .imageScaleType(ImageScaleType.EXACTLY_STRETCHED)
                    .build();

    private FragmentActivity mActivity;
    private Fragment mFragment;
    private List<Banner> mBanners;
    private ScreenSlidePagerAdapter mPagerAdapter;
    private ViewPager mViewPager;

    public BannerView(FragmentActivity activity, Fragment fragment) {
        mActivity = activity;
        mFragment = fragment;
    }

    public void update(View convertView) {
        mViewPager = (ViewPager) convertView;
        if (mBanners != null && !mBanners.isEmpty()) {
            if (mPagerAdapter == null) {
                mPagerAdapter = new ScreenSlidePagerAdapter(mFragment.getChildFragmentManager());
                mViewPager.setAdapter(mPagerAdapter);
            }
        }
        mViewPager.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (mOnBannerClickListener != null) {
                    mOnBannerClickListener.onBannerClick();
                }
            }
        });
    }

    class ScreenSlidePagerAdapter extends FragmentStatePagerAdapter {
        public ScreenSlidePagerAdapter(FragmentManager fm) {
            super(fm);
        }

        @Override
        public Fragment getItem(int position) {
            return new ScreenSlidePageFragment(mBanners.get(position).getImageUrl());
        }

        @Override
        public int getCount() {
            return mBanners == null ? 0 : mBanners.size();
        }
    }

    class ScreenSlidePageFragment extends Fragment {

        private String mUrl;

        ScreenSlidePageFragment(String url) {
            super();
            mUrl = url;
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container,
                                 Bundle savedInstanceState) {
            View view = inflater.inflate(R.layout.item_banner, container, false);
            if (view != null) {
                ImageView imageView = (ImageView) view.findViewById(R.id.item_banner_image);
                imageView.setLayoutParams(new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT));
                ImageLoader.getInstance().displayImage(mUrl, imageView, IMAGE_OPTIONS_SCALE_STRETCHED);
            }
            return view;
        }
    }
}

这是详细的错误列表:

11-10 18:12:19.217    1444-1444/? E/MessageQueue-JNI﹕ java.lang.IllegalArgumentException: No view found for id 0x7f05008b (com.example.viewpager:id/sub_viewpager) for fragment ScreenSlidePageFragment{428d8ea0 #0 id=0x7f05008b}
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:919)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1086)
        at android.support.v4.app.FragmentManagerImpl.dispatchActivityCreated(FragmentManager.java:1884)
        at android.support.v4.app.Fragment.performActivityCreated(Fragment.java:1514)
        at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947)
        at android.support.v4.app.FragmentManagerImpl.attachFragment(FragmentManager.java:1280)
        at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:672)
        at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1467)
        at android.support.v4.app.FragmentManagerImpl.executePendingTransactions(FragmentManager.java:472)
        at android.support.v4.app.FragmentPagerAdapter.finishUpdate(FragmentPagerAdapter.java:141)
        at android.support.v4.view.ViewPager.populate(ViewPager.java:1068)
        at android.support.v4.view.ViewPager.populate(ViewPager.java:914)
        at android.support.v4.view.ViewPager$3.run(ViewPager.java:244)
        at android.support.v4.view.ViewPager.completeScroll(ViewPager.java:1761)
        at android.support.v4.view.ViewPager.onInterceptTouchEvent(ViewPager.java:1896)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1854)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2211)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1912)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2211)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1912)
        at android.view.ViewGroup.dispatchTransformedTouchEvent(ViewGroup.java:2211)
        at android.view.ViewGroup.dispatchTouchEvent(ViewGroup.java:1912)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.superDispatchTouchEvent(PhoneWindow.java:2228)
        at com.android.internal.policy.impl.PhoneWindow.superDispatchTouchEvent(PhoneWindow.java:1471)
        at android.app.Activity.dispatchTouchEvent(Activity.java:2424)
        at com.android.internal.policy.impl.PhoneWindow$DecorView.dispatchTouchEvent(PhoneWindow.java:2176)
        at android.view.View.dispatchPointerEvent(View.java:7571)
        at android.view.ViewRootImpl$ViewPostImeInputStage.processPointerEvent(ViewRootImpl.java:3883)
        at android.view.ViewRootImpl$ViewPostImeInputStage.onProcess(ViewRootImpl.java:3778)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3379)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3429)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3398)
        at android.view.ViewRootImpl$AsyncInputStage.forward(ViewRootImpl.java:3483)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3406)
        at android.view.ViewRootImpl$AsyncInputStage.apply(ViewRootImpl.java:3540)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3379)
        at android.view.ViewRootImpl$InputStage.onDeliverToNext(ViewRootImpl.java:3429)
        at android.view.ViewRootImpl$InputStage.forward(ViewRootImpl.java:3398)
        at android.view.ViewRootImpl$InputStage.apply(ViewRootImpl.java:3406)
        at android.view.ViewRootImpl$InputStage.deliver(ViewRootImpl.java:3379)
        at android.view.ViewRootImpl.deliverInputEvent(ViewRootImpl.java:5419)
        at android.view.ViewRootImpl.doProcessInputEvents(ViewRootImpl.java:5399)
        at android.view.ViewRootImpl.enqueueInputEvent(ViewRootImpl.java:5370)
        at android.view.ViewRootImpl$WindowInputEventReceiver.onInputEvent(ViewRootImpl.java:5493)
        at android.view.InputEventReceiver.dispatchInputEvent(InputEventReceiver.java:182)
        at android.os.MessageQueue.nativePollOnce(Native Method)
        at android.os.MessageQueue.next(MessageQueue.java:132)
        at android.os.Looper.loop(Looper.java:124)
        at android.app.ActivityThread.main(ActivityThread.java:5289)
        at java.lang

Update:

我阅读了 FragmentManager 的源代码,终于得到了真正的原因:当片段想要在 viewpager 附加到其父级之前附加到 viewpager 时,会发生此异常。换句话说,在 getView() 方法返回之前,片段会膨胀。然后调用ViewPager容器的findViewById()方法,但ViewPager还处于detached状态,所以发现null,抛出IllegalArgumentException。

解决方案是创建一个自定义 ViewPager 并延迟设置适配器:

public class BannerViewPager extends ViewPager {
    PagerAdapter mPagerAdapter;

    @Override
    protected void onAttachedToWindow() {
        super.onAttachedToWindow();
        if (mPagerAdapter != null) {
            super.setAdapter(mPagerAdapter);
            mPageIndicator.setViewPager(this);
        }
    }

    @Override
    public void setAdapter(PagerAdapter adapter) {
    }

    public void storeAdapter(PagerAdapter pagerAdapter) {
        mPagerAdapter = pagerAdapter;
    }

    public BannerViewPager(Context context) {
        super(context);
    }

    public BannerViewPager(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

}

并且在 getView() 方法中,使用 storeAdapter() 而不是 setAdapter。

以下说法不正确。上面的话才是真正的原因。


终于我得到了答案。它由两部分组成。

  1. 在父 ViewPager 中我使用了FragmentPagerAdapter来保存碎片,但现在我使用FragmentStatePagerAdapter反而。这两者之间的区别可以在这里找到:FragmentPagerAdapter 和 FragmentStatePagerAdapter 的区别 https://stackoverflow.com/a/18748107/1301173.
    简单来说,当fragment停止时,FragmentPagerAdapter会存储更多信息。在这种情况下,父 ViewPager 中的第一个片段将停止但不会被销毁,同时该片段中的视图将被销毁。恢复后,片段尝试重新膨胀所有视图。但在此之前getView()方法被调用并且子ViewPager被重新创建,子FragmentManager尝试找到子ViewPager来保存那些以前存储的片段。因此会出现“java.lang.IllegalArgumentException:找不到 id 的视图”。

  2. 我用FragmentStatePagerAdapter替换FragmentPagerAdapter后,又出现了一个问题。当父片段(父视图页面中的第一个片段)停止、销毁和恢复时,子视图页面丢失。当选择第一个片段,不久之后选择第三个片段,最后重新选择第一个片段时,就会发生这种情况。
    我认为这是android sdk的一个bug。灵感来自here https://stackoverflow.com/questions/18977923/viewpager-with-nested-fragments?rq=1 and here https://stackoverflow.com/questions/15207305/getting-the-error-java-lang-illegalstateexception-activity-has-been-destroyed/15656428#15656428,我用一些刁钻的方法来解决这个问题。关键是,当父片段被销毁时,字段成员 --- mChildFragmentManager “最终会出现损坏的内部状态”,并且不会被完全清除。当父fragment重新创建时,mChildFragmentManager不为null,但是父fragment被销毁后,子fragment就已经被销毁了,由mChildFragmentManager管理。因此,子 ViewPager 在屏幕上显示一个空视图,它响应一个实际上不存在的假片段。有趣的是,在子ViewPager上向右滑动几次后,子片段和视图再次出现。

这是代码:

父适配器:

@Override
public View getView(int position, View convertView, ViewGroup parent) {
    if (convertView == null) {
        convertView = getBannerView(mParent);
    }
    mViewPager = (ViewPager) convertView;
    if (mBanners != null && !mBanners.isEmpty()) {
        if (mPagerAdapter == null) {
            FragmentManager childFM = mFragment.getChildFragmentManager();
            removeOldFragment(childFM);
            mPagerAdapter = new ScreenSlidePagerAdapter(childFM, mBanners);
            mViewPager.setAdapter(mPagerAdapter);
        }
    }
    return convertView;
}

关键方法:

    private void removeOldFragment(FragmentManager fm) {
        try {
            Field added = fm.getClass().getDeclaredField("mAdded");
            added.setAccessible(true);
            added.set(fm, null);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
        try {
            Field active = fm.getClass().getDeclaredField("mActive");
            active.setAccessible(true);
            active.set(fm, null);
        } catch (NoSuchFieldException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IllegalArgumentException:在 ViewPager 中找不到片段 id 的视图 --- ViewPager 的相关文章

随机推荐

  • 在 SQLite 中的 GROUP_CONCAT 函数中使用 ORDER BY 子句

    我不认为我可以使用ORDER BY里面的子句GROUP CONCAT功能 有谁知道一种棘手的方法来完成这种行为SQLite 我看到了这个question https stackoverflow com questions 1897352 s
  • 如何将由东北坐标和西南坐标组成的特定边界拟合到可见地图视图中?

    我需要在地图内适应特定的边界 我通过调用谷歌地理编码器并读取视口属性来获取边界 如下所示 northeast lat 30 4212235 lng 97 486942 southwest lat 30 1128403 lng 97 9991
  • 在加载的 ELF(.so 共享库)中挂钩并替换导出函数

    我正在编写一些 C 代码来将 so ELF 共享库 的某些函数加载到内存中 我的 C 代码应该能够重定向另一个加载到应用程序 程序内存中的 so 库的导出函数 这里有一些详细说明 Android 应用程序将加载多个 so 文件 我的 C 代
  • Google 登录:使用 google-auth Python 包时“未找到密钥 ID xxxx 的证书”

    我正在维护一个网站及其移动应用程序 iOS 和 Android 对于移动应用程序中的 Google 登录 我正在使用google auth Python 包 https github com googleapis google auth l
  • 知道任何体素图形 C++ 库吗? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 所以 我正在寻找带有 C 库 面向游戏 的体素图形引擎 只是为了好玩 这将是我第一次使用图形库 因此它不必非常复杂或强大 只需易于理解即可
  • 尽管allowtgtsessionkey注册表项无法检索TGT

    我正在尝试连接我们的 Windows 客户端应用程序以使用单点登录机制 我正在遵循可以找到的解释here http www javaactivedirectory com page id 196 我已经很难完成第一步 即获取登录用户的票证授
  • 尝试在构造函数中访问 @Inject bean 时出现 NullPointerException

    我有一个会话范围的 bean Named SessionScoped public class SessionBean implements Serializable private String someProperty public S
  • JTable更改列字体

    我正在制作一个表格 我想在其中制作具有更高字体大小的第一列 例如 在第 0 列中 我希望字体大小为 30 在第 1 3 列中 我希望字体大小为 13 这是我的代码 import java awt import java awt event
  • 当cmd以管理员身份运行时如何将输入发送到命令?

    我创建了一个将键盘输入发送到的应用程序cmd exe 这在运行时有效cmd作为普通用户但失败时cmd以管理员身份运行 这是我的代码 Var Wnd hwnd begin wnd FindWindow ConsoleWindowClass 0
  • 在 PostScript 中显示 Unicode 字符

    如何让我的 PostScript 程序显示 G 谱号字符Bravura https github com steinbergmedia bravura字体 根据这个SMuFL http www smufl org files smufl 0
  • 如何取数据?

    我正在学习使用神经网络 并且遇到了问题 我不知道如何转换神经网络的数据 据我了解 我需要对数据进行标准化 在标准化和学习之后 答案总是平均的 https jsfiddle net eoy7krzj https jsfiddle net eo
  • 奇怪的方法行为 - 函数的 ToString

    考虑这个代码片段 class Program static void Main string args Console WriteLine Test ToString static IEnumerable
  • 如何使用 Azure API Manager 缓存存储值策略存储 JSON 有效负载?

    再会 我尝试使用 缓存存储值 策略将传入的 JSON 负载存储到 Azure API Manager 内部缓存中 密钥将是有效负载内的字段之一 我能够提取密钥 但是当我尝试存储有效负载时 我收到错误 表达式求值失败 未将对象引用设置为对象的
  • 尝试使用 SQL 从多个表中删除

    我的应用程序中有 4 个表 User usession upklist 项目共享 最后三个表包含一个名为session id 在下面的代码中 括号中的部分用于获取所有session id值来自usession用户 awpeople 的表 问
  • Apache Beam 每用户会话窗口未合并

    我们有一个有用户的应用程序 每个用户每次使用我们的应用程序大约 10 40 分钟 我想根据发生的特定事件 例如 该用户已转换 该用户上次会话出现问题 该用户上次会话成功 在此之后 我想计算每天这些更高级别的事件 但这是一个单独的问题 为此
  • 如何在 Jupyter 中将变量从 javascript 传递到 python?

    据我了解 我应该能够打印变量foo在下面的代码片段中 from IPython display import HTML HTML print foo 相反 我看到以下错误消息 NameErrorTraceback most recent c
  • 在.NET中设置打印机“保留打印文档”属性

    这就是我们正在尝试做的事情 我们希望以一种不引人注目的方式获取客户在其计算机上打印的所有内容 我们所有的客户都运行 POS 系统并专门使用 Windows XP 并将其发送给我们 我们决定最好的方法是创建一个 c 向我们发送假脱机文件的应用
  • 如何将文本 URL 转换为 PHP 页面中的可点击链接?

    我确信这是一个非常简单 明显的答案 但我的大脑已经崩溃了 我似乎无法理解它 我有一个 PHP 站点 允许用户将信息发布到 mySQL 中的文本字段 这些帖子都可以在线查看 在发布 编辑模式下 该字段是 HTML 表单中的文本区域 在阅读模式
  • 在开发环境中覆盖ActionMailer的邮件地址

    在我的开发环境中 我在本地测试时使用生产数据库的副本 出于测试和防止向真实用户发送测试 开发电子邮件的原因 在开发模式下覆盖邮件地址的最佳方法是什么 我知道我可以在每个邮件程序中编写逻辑 但我有几个 最好将它们全部放在一个地方 我可以覆盖m
  • IllegalArgumentException:在 ViewPager 中找不到片段 id 的视图 --- ViewPager

    我遇到了困扰我好几天的问题 有一个ViewPager在主要活动中持有 3Fragments 作为选项卡片段 在里面first片段有一个ListView哪个持有一些观点 哪个是最重要的 另一个ViewPager 我想在子里保留一些照片View