gpt4 book ai didi

android - fragment 真的需要一个空的构造函数吗?

转载 作者:IT老高 更新时间:2023-10-28 12:51:25 25 4
gpt4 key购买 nike

我有一个带有多个参数的构造函数的 Fragment。我的应用在开发过程中运行良好,但在生产中我的用户有时会看到此崩溃:

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

我可以按照此错误消息的提示创建一个空的构造函数,但这对我来说没有意义,因为那时我必须调用一个单独的方法来完成设置 Fragment

我很好奇为什么这种崩溃只是偶尔发生。也许我使用 ViewPager 不正确?我自己实例化所有 Fragment 并将它们保存在 Activity 内的列表中。我不使用 FragmentManager 事务,因为我看到的 ViewPager 示例不需要它,并且在开发过程中一切似乎都在工作。

最佳答案

是的。

你不应该真的重写构造函数。您应该定义一个 newInstance() 静态方法并通过参数(包)传递任何参数

例如:

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

当然也可以这样获取参数:

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

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

然后你会像这样从 fragment 管理器中实例化:

@Override
public void onCreate(Bundle savedInstanceState) {
if (savedInstanceState == null){
getSupportFragmentManager()
.beginTransaction()
.replace(R.id.content, MyFragment.newInstance(
R.string.alert_title,
"Oh no, an error occurred!")
)
.commit();
}
}

这样,如果分离并重新附加,对象状态可以通过参数存储。很像附加到 Intent 的 bundle 。

原因 - 额外阅读

我想我会为想知道为什么的人解释原因。

如果您检查:https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/Fragment.java

你会看到Fragment类中的instantiate(..)方法调用了newInstance方法:

public static Fragment instantiate(Context context, String fname, @Nullable Bundle args) {
try {
Class<?> clazz = sClassMap.get(fname);
if (clazz == null) {
// Class not found in the cache, see if it's real, and try to add it
clazz = context.getClassLoader().loadClass(fname);
if (!Fragment.class.isAssignableFrom(clazz)) {
throw new InstantiationException("Trying to instantiate a class " + fname
+ " that is not a Fragment", new ClassCastException());
}
sClassMap.put(fname, clazz);
}
Fragment f = (Fragment) clazz.getConstructor().newInstance();
if (args != null) {
args.setClassLoader(f.getClass().getClassLoader());
f.setArguments(args);
}
return f;
} catch (ClassNotFoundException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (java.lang.InstantiationException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (IllegalAccessException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": make sure class name exists, is public, and has an"
+ " empty constructor that is public", e);
} catch (NoSuchMethodException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": could not find Fragment constructor", e);
} catch (InvocationTargetException e) {
throw new InstantiationException("Unable to instantiate fragment " + fname
+ ": calling Fragment constructor caused an exception", e);
}
}

http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#newInstance()解释为什么在实例化时它会检查访问器是 public 并且该类加载器允许访问它。

总的来说,这是一个非常讨厌的方法,但它允许 FragmentManger 杀死并重新创建带有状态的 Fragments。 (Android 子系统用 Activity 做类似的事情)。

示例类

我被问到很多关于调用 newInstance 的问题。不要将此与类方法混淆。这个整个类的例子应该显示用法。

/**
* 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...
}

关于android - fragment 真的需要一个空的构造函数吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10450348/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com