Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/207.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 使用FragmentPagerAdapter时如何获取现有片段_Android_Android Fragments_Fragmentpageradapter - Fatal编程技术网

Android 使用FragmentPagerAdapter时如何获取现有片段

Android 使用FragmentPagerAdapter时如何获取现有片段,android,android-fragments,fragmentpageradapter,Android,Android Fragments,Fragmentpageradapter,我无法通过活动使片段相互通信,该活动将FragmentPagerAdapter用作辅助类,该类实现选项卡的管理以及将ViewPager与关联的TabHost连接的所有详细信息。我已经实现了FragmentPagerAdapter,与Android示例项目Support4Demos提供的一样 主要问题是,当我既没有Id也没有标记时,如何从FragmentManager获取特定片段FragmentPagerAdapter正在创建片段并自动生成Id和标签。我根据以下帖子找到了问题的答案: 我学到的东西

我无法通过
活动
使片段相互通信,该活动将
FragmentPagerAdapter
用作辅助类,该类实现选项卡的管理以及将
ViewPager
与关联的
TabHost
连接的所有详细信息。我已经实现了
FragmentPagerAdapter
,与Android示例项目Support4Demos提供的一样


主要问题是,当我既没有Id也没有标记时,如何从
FragmentManager
获取特定片段
FragmentPagerAdapter
正在创建片段并自动生成Id和标签。

我根据以下帖子找到了问题的答案:

我学到的东西很少:

  • FragmentPagerAdapter
    中的
    getItem(int-position)
    对于该方法的实际作用是一个相当误导性的名称。它创建新片段,而不是返回现有片段。因此,在Android SDK中,应该将该方法重命名为类似于
    createItem(int-position)
    。所以这个方法不能帮助我们得到碎片
  • 根据文章中的解释,您应该将片段的创建留给
    FragmentPagerAdapter
    ,这意味着您没有提及片段或其标签。如果您有片段标记,则可以通过调用
    findFragmentByTag()
    FragmentManager
    轻松检索对它的引用。我们需要一种方法来找出给定页面位置的片段标签
  • 解决方案

    在类中添加以下helper方法以检索片段标记并将其发送到
    findframentbytag()
    方法

    private String getFragmentTag(int viewPagerId, int fragmentPosition)
    {
         return "android:switcher:" + viewPagerId + ":" + fragmentPosition;
    }
    

    注意!这与
    FragmentPagerAdapter
    在创建新片段时使用的方法相同。查看此链接

    请继续尝试此代码

    public class MYFragmentPAdp extends FragmentPagerAdapter {
    
        public MYFragmentPAdp(FragmentManager fm) {
            super(fm);
        }
    
        @Override
        public int getCount() {
            return 2;
        }
    
         @Override
         public Fragment getItem(int position) {
             if (position == 0)
                 Fragment fragment = new Fragment1();
             else (position == 1)
                 Fragment fragment = new Fragment2();
             return fragment;
         }
    }
    

    请参见从FragmentPagerAdapter返回碎片。确实依赖于您知道片段的索引-但是这将在getItem()中设置(仅在实例化时)

    我创建了这个方法,该方法用于获取对当前片段的引用

    public static Fragment getCurrentFragment(ViewPager pager, FragmentPagerAdapter adapter) {
        try {
            Method m = adapter.getClass().getSuperclass().getDeclaredMethod("makeFragmentName", int.class, long.class);
            Field f = adapter.getClass().getSuperclass().getDeclaredField("mFragmentManager");
            f.setAccessible(true);
            FragmentManager fm = (FragmentManager) f.get(adapter);
            m.setAccessible(true);
            String tag = null;
            tag = (String) m.invoke(null, pager.getId(), (long) pager.getCurrentItem());
            return fm.findFragmentByTag(tag);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } 
        return null;
    }
    

    我这样做的方式是定义WeakReference的哈希表,如下所示:

    protected Hashtable<Integer, WeakReference<Fragment>> fragmentReferences;
    
    技巧,因为它不依赖于FragmentPagerAdapter的实现方式。 当然,如果片段已由FragmentPagerAdapter释放,或者尚未创建,则getFragment将返回null


    如果有人发现这种方法有问题,欢迎评论。

    由@personne3000建议的解决方案很好,但它有一个问题:当活动进入后台并被系统杀死(为了获得一些可用内存)然后恢复时,
    碎片引用将为空,因为不会调用
    getItem

    下面的类处理这种情况:

    public abstract class AbstractHolderFragmentPagerAdapter<F extends Fragment> extends FragmentPagerAdapter {
    
        public static final String FRAGMENT_SAVE_PREFIX = "holder";
        private final FragmentManager fragmentManager; // we need to store fragment manager ourselves, because parent's field is private and has no getters.
    
        public AbstractHolderFragmentPagerAdapter(FragmentManager fm) {
            super(fm);
            fragmentManager = fm;
        }
    
        private SparseArray<WeakReference<F>> holder = new SparseArray<WeakReference<F>>();
    
        protected void holdFragment(F fragment) {
            holdFragment(holder.size(), fragment);
        }
    
        protected void holdFragment(int position, F fragment) {
            if (fragment != null)
                holder.put(position, new WeakReference<F>(fragment));
        }
    
        public F getHoldedItem(int position) {
            WeakReference<F> ref = holder.get(position);
            return ref == null ? null : ref.get();
        }
    
        public int getHolderCount() {
            return holder.size();
        }
    
        @Override
        public void restoreState(Parcelable state, ClassLoader loader) { // code inspired by Google's FragmentStatePagerAdapter implementation
            super.restoreState(state, loader);
            Bundle bundle = (Bundle) state;
            for (String key : bundle.keySet()) {
                if (key.startsWith(FRAGMENT_SAVE_PREFIX)) {
                    int index = Integer.parseInt(key.substring(FRAGMENT_SAVE_PREFIX.length()));
                    Fragment f = fragmentManager.getFragment(bundle, key);
                    holdFragment(index, (F) f);
                }
            }
        }
    
        @Override
        public Parcelable saveState() {
            Bundle state = (Bundle) super.saveState();
            if (state == null)
                state = new Bundle();
    
            for (int i = 0; i < holder.size(); i++) {
                int id = holder.keyAt(i);
                final F f = getHoldedItem(i);
                String key = FRAGMENT_SAVE_PREFIX + id;
                fragmentManager.putFragment(state, key, f);
            }
            return state;
        }
    }
    
    公共抽象类AbstractHolderFragmentPagerAdapter扩展了FragmentPagerAdapter{
    公共静态最终字符串片段\u SAVE\u PREFIX=“holder”;
    private final FragmentManager FragmentManager;//我们需要自己存储片段管理器,因为父字段是私有的,没有getter。
    公共摘要持有者FragmentPageRadapter(碎片管理器fm){
    超级(fm);
    碎片管理器=fm;
    }
    私人SparseArray持有人=新SparseArray();
    受保护的空碎片(F碎片){
    holdFragment(holder.size(),fragment);
    }
    受保护的void holdFragment(内部位置,F片段){
    if(片段!=null)
    保持器放置(位置,新WeakReference(碎片));
    }
    公共F getHoldedItem(内部位置){
    WeakReference ref=保持架获取(位置);
    return ref==null?null:ref.get();
    }
    public int getHolderCount(){
    返回保持架。大小();
    }
    @凌驾
    public void restoreState(Parcelable state,ClassLoader){//源于Google的FragmentStatePagerAdapter实现的代码
    super.restoreState(州、装载机);
    Bundle=(Bundle)状态;
    for(字符串键:bundle.keySet()){
    if(key.startsWith(片段\保存\前缀)){
    int index=Integer.parseInt(key.substring(FRAGMENT\u SAVE\u PREFIX.length());
    Fragment f=fragmentManager.getFragment(bundle,key);
    保持片段(索引,(F)F);
    }
    }
    }
    @凌驾
    公共包裹存储状态(){
    Bundle state=(Bundle)super.saveState();
    if(state==null)
    state=newbundle();
    对于(int i=0;i
    问题摘要 注意:在这个答案中,我将参考
    FragmentPagerAdapter
    及其源代码。但一般解决方案也应适用于
    片段StatePageRadapter

    如果您正在阅读本文,您可能已经知道,
    FragmentPagerAdapter
    /
    FragmentStatePagerAdapter
    旨在为您的
    ViewPager
    创建
    片段,但在活动重新创建时(无论是通过设备旋转还是通过系统关闭应用程序以恢复内存)这些
    片段
    不会被再次创建,而是它们的片段。现在假设您的
    活动
    需要获得对这些
    片段的引用
    ,才能对它们进行操作。对于这些创建的
    片段
    您没有
    id
    标记
    ,因为
    FragmentPagerAdapter
    。所以问题是如何在没有这些信息的情况下获得对它们的引用

    当前解决方案的问题:依赖内部代码 我在这方面看到了很多解决方案
    public Fragment getFragment(int fragmentId) {
        WeakReference<Fragment> ref = fragmentReferences.get(fragmentId);
        return ref == null ? null : ref.get();
    }
    
    "android:switcher:" + viewId + ":" + position
    
    public abstract class AbstractHolderFragmentPagerAdapter<F extends Fragment> extends FragmentPagerAdapter {
    
        public static final String FRAGMENT_SAVE_PREFIX = "holder";
        private final FragmentManager fragmentManager; // we need to store fragment manager ourselves, because parent's field is private and has no getters.
    
        public AbstractHolderFragmentPagerAdapter(FragmentManager fm) {
            super(fm);
            fragmentManager = fm;
        }
    
        private SparseArray<WeakReference<F>> holder = new SparseArray<WeakReference<F>>();
    
        protected void holdFragment(F fragment) {
            holdFragment(holder.size(), fragment);
        }
    
        protected void holdFragment(int position, F fragment) {
            if (fragment != null)
                holder.put(position, new WeakReference<F>(fragment));
        }
    
        public F getHoldedItem(int position) {
            WeakReference<F> ref = holder.get(position);
            return ref == null ? null : ref.get();
        }
    
        public int getHolderCount() {
            return holder.size();
        }
    
        @Override
        public void restoreState(Parcelable state, ClassLoader loader) { // code inspired by Google's FragmentStatePagerAdapter implementation
            super.restoreState(state, loader);
            Bundle bundle = (Bundle) state;
            for (String key : bundle.keySet()) {
                if (key.startsWith(FRAGMENT_SAVE_PREFIX)) {
                    int index = Integer.parseInt(key.substring(FRAGMENT_SAVE_PREFIX.length()));
                    Fragment f = fragmentManager.getFragment(bundle, key);
                    holdFragment(index, (F) f);
                }
            }
        }
    
        @Override
        public Parcelable saveState() {
            Bundle state = (Bundle) super.saveState();
            if (state == null)
                state = new Bundle();
    
            for (int i = 0; i < holder.size(); i++) {
                int id = holder.keyAt(i);
                final F f = getHoldedItem(i);
                String key = FRAGMENT_SAVE_PREFIX + id;
                fragmentManager.putFragment(state, key, f);
            }
            return state;
        }
    }
    
    public class SomeActivity extends Activity {
        private FragmentA m1stFragment;
        private FragmentB m2ndFragment;
    
        // other code in your Activity...
    
        private class CustomPagerAdapter extends FragmentPagerAdapter {
            // other code in your custom FragmentPagerAdapter...
    
            public CustomPagerAdapter(FragmentManager fm) {
                super(fm);
            }
    
            @Override
            public Fragment getItem(int position) {
                // Do NOT try to save references to the Fragments in getItem(),
                // because getItem() is not always called. If the Fragment
                // was already created then it will be retrieved from the FragmentManger
                // and not here (i.e. getItem() won't be called again).
                switch (position) {
                    case 0:
                        return new FragmentA();
                    case 1:
                        return new FragmentB();
                    default:
                        // This should never happen. Always account for each position above
                        return null;
                }
            }
    
            // Here we can finally safely save a reference to the created
            // Fragment, no matter where it came from (either getItem() or
            // FragmentManger). Simply save the returned Fragment from
            // super.instantiateItem() into an appropriate reference depending
            // on the ViewPager position.
            @Override
            public Object instantiateItem(ViewGroup container, int position) {
                Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
                // save the appropriate reference depending on position
                switch (position) {
                    case 0:
                        m1stFragment = (FragmentA) createdFragment;
                        break;
                    case 1:
                        m2ndFragment = (FragmentB) createdFragment;
                        break;
                }
                return createdFragment;
            }
        }
    
        public void someMethod() {
            // do work on the referenced Fragments, but first check if they
            // even exist yet, otherwise you'll get an NPE.
    
            if (m1stFragment != null) {
                // m1stFragment.doWork();
            }
    
            if (m2ndFragment != null) {
                // m2ndFragment.doSomeWorkToo();
            }
        }
    }
    
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Fragment createdFragment = (Fragment) super.instantiateItem(container, position);
        // get the tags set by FragmentPagerAdapter
        switch (position) {
            case 0:
                String firstTag = createdFragment.getTag();
                break;
            case 1:
                String secondTag = createdFragment.getTag();
                break;
        }
        // ... save the tags somewhere so you can reference them later
        return createdFragment;
    }
    
    WeakReference<Fragment> m1stFragment = new WeakReference<Fragment>(createdFragment);
    // ...and access them like so
    Fragment firstFragment = m1stFragment.get();
    if (firstFragment != null) {
        // reference hasn't been cleared yet; do work...
    }
    
    @Override
    public Object instantiateItem(ViewGroup container, int position) {
        Object value =  super.instantiateItem(container, position);
    
        if (position == 0) {
            someFragment = (SomeFragment) value;
        } else if (position == 1) {
            anotherFragment = (AnotherFragment) value;
        }
    
        return value;
    }
    
    @Override
    public void onAttach(Context context){
        super.onAttach(context);
        MainActivity.fragId = getId();
    }
    
    Fragment f = getSupportFragmentManager.findFragmentById(fragId);
    
    public class MyActivity extends AppCompatActivity {
    
        Fragment0 tab0; Fragment1 tab1;
    
        @Override protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.myLayout);
            ViewPager viewPager = (ViewPager) findViewById(R.id.myViewPager);
            MyPagerAdapter adapter = new MyPagerAdapter(getSupportFragmentManager());
            viewPager.setAdapter(adapter);
            ((TabLayout) findViewById(R.id.tabs)).setupWithViewPager(viewPager);
    
            adapter.startUpdate(viewPager);
            tab0 = (Fragment0) adapter.instantiateItem(viewPager, 0);
            tab1 = (Fragment1) adapter.instantiateItem(viewPager, 1);
            adapter.finishUpdate(viewPager);
        }
    
        class MyPagerAdapter extends FragmentPagerAdapter {
    
            public MyPagerAdapter(FragmentManager manager) {super(manager);}
    
            @Override public int getCount() {return 2;}
    
            @Override public Fragment getItem(int position) {
                if (position == 0) return new Fragment0();
                if (position == 1) return new Fragment1();
                return null;  // or throw some exception
            }
    
            @Override public CharSequence getPageTitle(int position) {
                if (position == 0) return getString(R.string.tab0);
                if (position == 1) return getString(R.string.tab1);
                return null;  // or throw some exception
            }
        }
    }
    
    @Override
    public void onAttach(Activity activity) {
        super.onAttach(activity);
        try {
            mListener = (OnListInteractionListener) activity;
            mListener.setListFrag(this);
        } catch (ClassCastException e) {
            throw new ClassCastException(activity.toString()
                    + " must implement OnFragmentInteractionListener");
        }
    }
    
    @Override
    public void setListFrag(MyListFragment lf) {
        if (mListFragment == null) {
            mListFragment = lf;
        }
    }
    
    if (savedInstanceState != null) {
        if (mListFragment != null)
            mListFragment.setListItems(items);
    }
    
    public interface Callbacks {
        public void addFragment (Fragment fragment);
        public void removeFragment (Fragment fragment);
    }
    
    public class HostingActivity extends AppCompatActivity implements ViewPagerFragment.Callbacks {
    
        private LinkedHashSet<Fragment> mFragments = new LinkedHashSet<>();
    
        @Override
        public void addFragment (Fragment fragment) {
            mFragments.add(fragment);
        }
    
        @Override
        public void removeFragment (Fragment fragment) {
            mFragments.remove(fragment);
        }
    }
    
    public class ViewPagerFragment extends Fragment {
    
        private Callbacks mCallbacks;
    
        public interface Callbacks {
            public void addFragment (Fragment fragment);
            public void removeFragment (Fragment fragment);
        } 
    
        @Override
        public void onAttach (Context context) {
            super.onAttach(context);
            mCallbacks = (Callbacks) context;
            // Add this fragment to the HashSet in the hosting activity
            mCallbacks.addFragment(this);
        }
    
        @Override
        public void onDetach() {
            super.onDetach();
            // Remove this fragment from the HashSet in the hosting activity
            mCallbacks.removeFragment(this);
            mCallbacks = null;
        }
    }
    
    public class ViewPagerAdapter extends FragmentPagerAdapter {
    
        private final Map<Integer, Reference<Fragment>> fragments = new HashMap<>();
        private final List<Callable0<Fragment>> initializers = new ArrayList<>();
        private final List<String> titles = new ArrayList<>();
    
        public ViewPagerAdapter(FragmentManager fm) {
            super(fm);
        }
    
        void addFragment(Callable0<Fragment> initializer, String title) {
            initializers.add(initializer);
            titles.add(title);
        }
    
        public Optional<Fragment> getFragment(int position) {
            return Optional.ofNullable(fragments.get(position).get());
        }
    
        @Override
        public Fragment getItem(int position) {
            Fragment fragment =  initializers.get(position).execute();
            return fragment;
        }
    
        @Override
        public Object instantiateItem(ViewGroup container, int position) {
            Fragment fragment = (Fragment) super.instantiateItem(container, position);
            fragments.put(position, new WeakReference<>(fragment));
            return fragment;
        }
    
        @Override
        public int getCount() {
            return initializers.size();
        }
    
        @Override
        public CharSequence getPageTitle(int position) {
            return titles.get(position);
        }
    }