难道片段真的需要一个空的构造?片段

2023-09-12 00:04:40 作者:魔法少女猪壮壮

我有多个参数的构造函数的片段,一切testphase过程中工作得很好,但现在经过约300名用户下载的应用程序,我有一个occurence是例外的:

I have a fragment with a Constructor with multiple arguments, everything worked fine during testphase but now after about 300 users downloaded the app, i have ONE occurence of that exception:

android.support.v4.app.Fragment$InstantiationException: Unable to instantiate fragment 
make sure class name exists, is public, and has an empty constructor that is public

我的意思是我可以提供不同的构造,但并不作过多的意义,因为我将不得不调用其他方法来真正建立片段。

I mean i could provide a different Constructor but that doesn't make too much sense since i would then have to call another method to really set up the Fragment.

我很好奇,为什么会发生零星的,而不是总是,也许即时通讯使用零散Viewpager绝对错误的,因为我实例化所有碎片自己,并将它们保存到内部的活动列表。我不使用 FragmentManager 交易的东西,距今约碎片Viewpager的例子​​也不是很清楚这一点,最终一切都能正常工作。

I'm curious as to why that is happening sporadically and not always and maybe im using the Fragmented Viewpager just wrong, because i instantiate all the fragments myself and save them into a list inside the activity. I don't use the FragmentManager transaction stuff, since the example about Fragmented Viewpager was not very clear about that and in the end everything worked fine.

推荐答案

是的,他们做的。

您真的不应该是反正覆盖的构造。你应该有一个定义的的newInstance()静态方法,并通过参数传递任何参数(包)

You shouldn't really be overriding the constructor anyway. You should have a newInstance() static method defined and pass any parameters via arguments (bundle)

例如:

public static final AlertFragment newInstance(int title, String message)
{
    AlertFragment f = new AlertFragment();
    Bundle bdl = new Bundle(2);
    bdl.putInt(EXTRA_TITLE, title);
    bdl.putString(EXTRA_MESSAGE, message);
    f.setArguments(bdl);
    return f;
}

当然抓住的args是这样的:

And of course grabbing the args this way:

@Override
public void onCreate(Bundle savedInstanceState)
{
    title = getArguments().getInt(EXTRA_TITLE);
    message = getArguments().getString(EXTRA_MESSAGE);

    //...
    //etc
    //...
}

然后你会实例化从片段经理像这样:

Then you would instantiate from your fragment manager like so:

public onCreate(Bundle savedInstanceState) {
    if(savedInstanceState == null){
        getSupportFragmentManager()
            .beginTransaction()
            .replace(R.id.content,AlertFragment.newInstance(
                R.string.alert_title,
                "Oh noes an error occured!")
            )
            .commit();
    }
}

这样,如果分离并重新连接对象的状态可以通过参数进行存储。就像附在意图包。

This way if detached and re-attached the object state can be stored through the arguments. Much like bundles attached to Intents.

原因 - 额外的阅读

我想我会为人们想知道为什么。

I thought I would explain why for people wondering why.

如果您检查:https://android.googlesource.com/platform/frameworks/support/+/refs/heads/master/v4/java/android/support/v4/app/Fragment.java

您将看到实例化(..)片段类方法调用的newInstance 方法。 http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#newInstance()解释了为什么,在实例化时它会检查该访问是公开而这种类加载器允许它访问。

You will see the instantiate(..) method in the Fragment class calls the newInstance method. http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#newInstance() Explains why, upon instantiation it checks that the accessor is public and that that class loader allows access to it.

这是一个pretty的讨厌的方法,这一切的一切,但它允许 FragmentManger 杀死并重新创建片段与状态。 (Android的子系统做类似的事情,与活动)。

It's a pretty nasty method all in all, but it allows the FragmentManger to kill and recreate Fragments with states. (The Android subsystem does similar things with Activities).

示例类

我被问了很多关于调用的newInstance ,(不与类方法混淆。这整个阶级的例子应该显示的用法。

I get asked alot about calling newInstance,(do not confuse this with the class method. This whole class example should show the usage.

/**
 * Created by chris on 21/11/2013
 */
public class StationInfoAccessibilityFragment extends BaseFragment implements JourneyProviderListener {

    public static final StationInfoAccessibilityFragment newInstance(String crsCode) {
        StationInfoAccessibilityFragment fragment = new StationInfoAccessibilityFragment();

        final Bundle args = new Bundle(1);
        args.putString(EXTRA_CRS_CODE, crsCode);
        fragment.setArguments(args);

        return fragment;
    }

    // Views
    LinearLayout mLinearLayout;

    /**
     * Layout Inflater
     */
    private LayoutInflater mInflater;
    /**
     * Station Crs Code
     */
    private String mCrsCode;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mCrsCode = getArguments().getString(EXTRA_CRS_CODE);
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        mInflater = inflater;
        return inflater.inflate(R.layout.fragment_station_accessibility, container, false);
    }

    @Override
    public void onViewCreated(View view, Bundle savedInstanceState) {
        super.onViewCreated(view, savedInstanceState);
        mLinearLayout = (LinearLayout)view.findViewBy(R.id.station_info_accessibility_linear);
        //Do stuff
    }

    @Override
    public void onResume() {
        super.onResume();
        getActivity().getSupportActionBar().setTitle(R.string.station_info_access_mobility_title);
    }

    // Other methods etc...
}