程序问答   发布时间:2022-06-01  发布网站:大佬教程  code.js-code.com
大佬教程收集整理的这篇文章主要介绍了使用自定义对象创建片段大佬教程大佬觉得挺不错的,现在分享给大家,也给大家做个参考。

如何解决使用自定义对象创建片段?

开发过程中遇到使用自定义对象创建片段的问题如何解决?下面主要结合日常开发的经验,给出你关于使用自定义对象创建片段的解决方法建议,希望对你解决使用自定义对象创建片段有所启发或帮助;

我用这种方式创建了一个带有自定义对象的片段:

public class SlIDeFragment extends Fragment {

    SlIDeData data;

    public static SlIDeFragment newInstance(SlIDeData data) {
        SlIDeFragment fragment = new SlIDeFragment(data);
        return fragment;
    }

    public SlIDeFragment() {
    }

    public SlIDeFragment(SlIDeData data) {
        this.data = data;
    }

    ...
}

我意识到这是错误的,如果 AndroID 重新创建片段,它会崩溃(它使用默认构造函数,因此数据为空)。

阅读这篇文章后,我看到我应该做这样的事情:

    public class SlIDeFragment extends Fragment {
    
        SlIDeData data;
    
        public static SlIDeFragment newInstance(SlIDeData data) {
            SlIDeFragment fragment = new SlIDeFragment(data);
            Bundle b = new Bundle();
            b.putParcelable("data",data);
            fragment.setArguments();
            return fragment;
        }
    
        public SlIDeFragment() {
        }
    
        public SlIDeFragment(SlIDeData data) {
            this.data = data;
        }
    
       @OverrIDe
        public VIEw onCreateVIEw(LayoutInflater inflater,VIEwGroup container,Bundle savedInstanceStatE) {
    
            VIEw _fragment = inflater.inflate(R.layout.fragment_slIDe,container,falsE);
            Bundle b = getArguments();
            data = b.getParcelable("data");
            return _fragment;
        }
    ...
}

所以我应该把 SlIDeData 作为 Parcelable Object,但问题是这个对象有点复杂

public class SlIDeData {

    List<SlIDemessageData> messages;
    int BACkgroundcolor;
    SlIDebuttonType buttonType;
    SlIDebuttonInterface Listener;
}

public class SlIDemessageData {

    String text;
    int textColour;
}

public enum SlIDebuttonType {
    CLOSE,PREVIoUS,NEXT
}

public interface SlIDebuttonInterface {
    voID clickOnSlIDebutton();
}

为了使这个parcelable,我想使用:

  • writeList 和 readList 用于“消息”。
  • writeInt 和 readInt 用于“BACkgroundcolor”和“textcolor”。
  • writeString 和 readString 用于“文本”。
  • writeInt(buttonType.ordinal()) 和 SlIDebuttonType.values()[in.readInt()] 用于“buttonType”。

但是没有办法让“Listener”属性可以被parcel(这是正常的,没有意义)。

那么,我该如何解决这个问题?如果片段是由 AndroID 重新创建的,我如何使我的幻灯片数据持久化?

更新:

虑到 game over 评论,我尝试将 FragmentFactory 类子类化,但在这种情况下我不能这样做。 我使用 FactoryFragment 创建我的片段,但这种情况很特殊。我正在为 FragmentAdapter 创建这个片段。

我有这个:

public class SlIDeAdapter extends FragmentStatePagerAdapter {

    ...

    public voID addSlIDe(SlIDeData data)
    {
        SlIDeFragment slIDe = SlIDeFragment.newInstance(data);
        listofFragments.add(slIDE);
        notifyDataSetChanged();
    }

    ...
}

还有这个(我在游戏结束评论后添加了更多数据):

public class SlIDeVIEwerFragment extends Fragment {

    public static SlIDeVIEwerFragment newInstance() {
        return new SlIDeVIEwerFragment();
    }

    public SlIDeVIEwerFragment() {
    }

    public voID onCreate(Bundle savedInstanceStatE) {
        super.onCreate(savedInstanceStatE);

        if(savedInstanceState != null)
            data = savedInstanceState.getBundle("data");
    }

    public voID onSaveInstanceState(Bundle outStatE) {
        super.onSaveInstanceState(outStatE);
        outState.putBundle("data",data);
    }

    public voID setData(Bundle _data)
    {
        data = _data;
    }

    @OverrIDe
    public VIEw onCreateVIEw(@NonNull LayoutInflater inflater,Bundle savedInstanceStatE) {

        ... 

       FragmentActivity activity = getActivity();
       FragmentManager fragmentManager = activity.getSupportFragmentManager();
       mSlIDeAdapter = new SlIDeAdapter(fragmentManager);
       adapter.SETVALue(mSlIDeAdapter);
       slIDeList = viewmodel.getSlIDeListData();
       slIDeList.observe(myActivity,this::slIDeListChanged);

        return vIEw;
    }

    private voID buildSlIDes() {

        mSlIDeAdapter.clearSlIDes();
        for(int index = 0; index < slIDes.size(); index++)
        {
            SlIDeData slIDe = slIDes.get(indeX);
            mSlIDeAdapter.addSlIDe(slIDE);
        }
    }

   ...
}

我正在以这种方式创建我的 SlIDeVIEwerFragment:

    final FragmentManager fm = getSupportFragmentManager();
    FragmentFactory ff = fm.getFragmentFactory();
    Fragment fr = ff.instantiate(getClassLoader(),SlIDeVIEwerFragment.class.getname());
    Fragmenttransaction ft = fm.begintransaction();
    ft.setReorderingallowed(true);
    ft.add(R.ID.frame_content,fr,SlIDeVIEwerFragment.class.getname());

    Bundle _data = new Bundle();
    _data.puTint("content_type",2);
    ((BaseFragment) fr).setData(_data);

    ft.setCustomAnimations(androID.R.animator.fade_in,androID.R.animator.fade_out);
    ft.commit();
    fm.executePendingtransactions();

由于我在这里没有使用 FragmentFactory,我如何以安全的方式重新创建我的 SlIDeFragment?

也许问题在于我如何使用实例化构建 SlIDeVIEwerFragment?@R_391_10675@用 SlIDeVIEwerFragment.newInstance(data) 和 FragmentFactory 的子类来使用带参数的构造函数创建 SlIDeVIEwerFragment 吗?

解决方法

好的,所以你的问题是,是的,

1.) 需要将数据作为参数传入Fragment,否则进程死亡会吃掉它

但是

2.) FragmentPagerAdapter/FragmentStatePagerAdapter 仅在 getItem() 尚未添加时实例化 Fragment,因此使用诸如 pagerAdapter.addFragment(fragment) 之类的东西是一种反模式,会杀死您的代码。如果您想动态创建对象,您需要将 SlideData 传递给适配器,并在 SlideFragment 中为提供的位置创建一个 pagerAdapter.getItem(),使用 SlideData 作为来自正确的参数位置。即使在进程终止后,此 SlideData 也必须正确构造才能使其正常工作。

或者,你可以用0初始化一个ViewPager,然后动态添加片段,只要使用如下代码:

public class DynamicFragmentPagerAdapter extends PagerAdapter {
    private static final String TAG = "DynamicFragmentPagerAdapter";
  
    private final FragmentManager fragmentManager;
  
    public static abstract class FragmentIdentifier implements Parcelable {
        private final String fragmentTag;
        private final Bundle args;
      
        public FragmentIdentifier(@NonNull String fragmentTag,@Nullable Bundle args) {
            this.fragmentTag = fragmentTag;
            this.args = args;
        }
      
        protected FragmentIdentifier(Parcel in) {
            fragmentTag = in.readString();
            args = in.readBundle(getClass().getClassLoader());
        }

        @Override
        public void writeToParcel(Parcel dest,int flags) {
            dest.writeString(fragmentTag);
            dest.writeBundle(args);
        }
      
        protected final Fragment newFragment() {
            Fragment fragment = createFragment();
            Bundle oldArgs = fragment.getArguments();
            Bundle newArgs = new Bundle();
            if(oldArgs != null) {
                newArgs.putAll(oldArgs);
            }
            if(args != null) {
                newArgs.putAll(args);
            }
            fragment.setArguments(newArgs);
            return fragment;
        }

        protected abstract Fragment createFragment();
    }
  
    private ArrayList<FragmentIdentifier> fragmentIdentifiers = new ArrayList<>();

    private Fragmenttransaction currenttransaction = null;

    private Fragment currentPriMaryItem = null;

    public DynamicFragmentPagerAdapter(FragmentManager fragmentManager) {
        this.fragmentManager = fragmentManager;
    }

    privatE int findIndexIfAdded(FragmentIdentifier fragmentIdentifier) {
        for (int i = 0,size = fragmentIdentifiers.size(); i < size; i++) {
            FragmentIdentifier identifier = fragmentIdentifiers.get(i);
            if (identifier.fragmentTag.equals(fragmentIdentifier.fragmentTag)) {
                return i;
            }
        }
        return -1;
    }

    public void addFragment(FragmentIdentifier fragmentIdentifier) {
        if (findIndexIfAdded(fragmentIdentifier) < 0) {
            fragmentIdentifiers.add(fragmentIdentifier);
            notifyDataSetChanged();
        }
    }

    public void removeFragment(FragmentIdentifier fragmentIdentifier) {
        int index = findIndexIfAdded(fragmentIdentifier);
        if (index >= 0) {
            fragmentIdentifiers.remove(indeX);
            notifyDataSetChanged();
        }
    }

    @Override
    public int getCount() {
        return fragmentIdentifiers.size();
    }

    @Override
    public void startupdate(@NonNull ViewGroup container) {
        if (container.getId() == View.NO_ID) {
            throw new IllegalStateException("ViewPager with adapter " + this
                    + " requires a view id");
        }
    }

    @SuppressWarnings("ReferenceEquality")
    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container,int position) {
        if (currenttransaction == null) {
            currenttransaction = fragmentManager.begintransaction();
        }
        final FragmentIdentifier fragmentIdentifier = fragmentIdentifiers.get(position);
        // Do we already have this fragment?
        final String name = fragmentIdentifier.fragmentTag;
        Fragment fragment = fragmentManager.findFragmentByTag(Name);
        if (fragment != null) {
            currenttransaction.attach(fragment);
        } else {
            fragment = fragmentIdentifier.newFragment();
            currenttransaction.add(container.getId(),fragment,fragmentIdentifier.fragmentTag);
        }
        if (fragment != currentPriMaryItem) {
            fragment.setMenuVisibility(false);
            fragment.setUservisibleHint(false);
        }
        return fragment;
    }

    @Override
    public void destroyItem(@NonNull ViewGroup container,int position,@NonNull Object object) {
        if (currenttransaction == null) {
            currenttransaction = fragmentManager.begintransaction();
        }
        currenttransaction.detach((Fragment) object);
    }

    @SuppressWarnings("ReferenceEquality")
    @Override
    public void setPriMaryItem(@NonNull ViewGroup container,@NonNull Object object) {
        Fragment fragment = (Fragment) object;
        if (fragment != currentPriMaryItem) {
            if (currentPriMaryItem != null) {
                currentPriMaryItem.setMenuVisibility(false);
                currentPriMaryItem.setUservisibleHint(false);
            }
            fragment.setMenuVisibility(true);
            fragment.setUservisibleHint(true);
            currentPriMaryItem = fragment;
        }
    }

    @Override
    public void finishupdate(@NonNull ViewGroup container) {
        if (currenttransaction != null) {
            currenttransaction.commitNowAllowingStateLoss();
            currenttransaction = null;
        }
    }

    @Override
    public Boolean isViewFromObject(@NonNull View view,@NonNull Object object) {
        return ((Fragment) object).getView() == view;
    }

    @Override
    public Parcelable saveState() {
        Bundle bundle = new Bundle();
        bundle.putParcelableArrayList("fragmentIdentifiers",fragmentIdentifiers);
        return bundle;
    }

    @Override
    public void restoreState(Parcelable state,ClassLoader loader) {
        Bundle bundle = ((BundlE)statE);
        bundle.setClassLoader(loader);
        fragmentIdentifiers = bundle.getParcelableArrayList("fragmentIdentifiers");
    }
}

3.) 您不能将侦听器传递给 Fragment。有 3 种从片段进行通信的方式:

  • a.) 通过 fragment.setTargetFragment(),但前几天已弃用。

  • b.) 通过 FragmentResultListener,但不能保证您的 Fragment 将由 Fragment 创建,而不是由 Activity 创建。此外,适配器永远不会终止“为了结果”,因此在这种情况下这不起作用。

  • c.) SlideFragment 应公开由父片段或主机活动实现的接口 SlideFragment.SlideButtonInterface

为此,您需要进行分层查找:

private SlideButtonInterface slideButtonInterface = null;

@Override
protected void onCreate(Bundle savedInstanceStatE) {
    super.onCreate(savedInstanceStatE);

    Fragment parentFragment = null;
    while((parentFragment = getParentFragment()) != null) {
        if(parentFragment instanceof SlideButtonInterfacE) {
            this.slideButtonInterface = (SlideButtonInterfacE) parentFragment;
            break;
        }
    }

    if(slideButtonInterface == null) {
        slideButtonInterface = (SlideButtonInterfacE)getActivity();
    }
}

这样,父片段或活动都可以处理此片段的事件,而无需从外部显式传入。

大佬总结

以上是大佬教程为你收集整理的使用自定义对象创建片段全部内容,希望文章能够帮你解决使用自定义对象创建片段所遇到的程序开发问题。

如果觉得大佬教程网站内容还不错,欢迎将大佬教程推荐给程序员好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。
标签: