我正在使用遗留代码,我在此函数中发现了一个不一致的行为:
@Override
public void openFragment(final Class<? extends BaseFragment> fragmentClass,
final boolean addToBackStack,
final Bundle args)
{
long delay = 0;
if (mDrawerLayout.isDrawerOpen(GravityCompat.START)) {
delay = getResources().getInteger(android.R.integer.config_shortAnimTime) * 2;
}
// FIXME: quick fix, but not all cases
final Bundle args666 = args != null ? (Bundle) args.clone() : null;
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
doOpenFragment(fragmentClass, addToBackStack, args666);
}
}, delay);
closeDrawer();
}
protected void doOpenFragment(final Class<? extends BaseFragment> fragmentClass,
final boolean addToBackStack,
final Bundle args)
{
try {
if (getSupportFragmentManager().getBackStackEntryCount() >= 1) {
showNavigationIcon();
}
hideKeyboard();
BaseFragment fragment = createFragment(fragmentClass, args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
fragment.initTransactionAnimation(transaction);
String tag = getTag(fragment);
transaction.add(R.id.container, fragment, tag);
if (addToBackStack) {
transaction.addToBackStack(tag);
}
transaction.commitAllowingStateLoss();
hideLastFragment(0);
} catch (Exception e) {
Sentry.captureException(e, "Error opening fragment");
}
}
openFragment
获取非空的Bundle args,但doOpenFragment
将获得空Bundle。通过调用commitAllowingStateLoss()
快速修复可以使用Bundle.clone():
final Bundle args666 = (Bundle) args.clone();
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
doOpenFragment(fragmentClass, addToBackStack, args666);
}
}, delay);
它不会处理所有情况,deepCopy
仅在api26中可用。
[更新
我玩@ Pavel 的解决方案,事情变得怪异
final Bundle args666 = args != null ? cloneThroughSerialization(args) : args;
final Bundle args777 = args != null ? (Bundle) args.clone() : args;
[UPDATE2]
实际上,问题不在postDelayed
来电。让我们看一下调用堆栈:
在goRightToTheCollectionScreen
中创建并打包了Bundle(没有任何可疑,之后没有变异)。
我想,openFragmentsChain
内的两次调用中的问题来源:
public void openRootFragmentsChain(Class<? extends BaseFragment> fragmentClass,
List<Class<? extends BaseFragment>> fragmentClasses,
boolean addToBackStack,
Bundle args)
{
openFragmentsChain(fragmentClasses, addToBackStack, args);
openFragment(fragmentClass, true, args);
}
public void openFragmentsChain(List<Class<? extends BaseFragment>> fragmentClasses,
boolean addToBackStack,
Bundle args)
{
try {
for (int i = 0; i < fragmentClasses.size(); i++) {
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
BaseFragment fragment = createFragment(fragmentClasses.get(i), args);
String tag = getTag(fragment);
transaction.add(R.id.container, fragment, tag);
if (addToBackStack) {
transaction.addToBackStack(tag);
}
if (i != fragmentClasses.size() - 1) {
transaction.hide(fragment);
}
transaction.commitAllowingStateLoss();
}
if (fragmentClasses.size() >= 1) {
updateDrawer();
}
} catch (Exception e) {
Sentry.captureException(e, "Error opening fragment chain");
}
}
protected void doOpenFragment(final Class<? extends BaseFragment> fragmentClass,
final boolean addToBackStack,
final Bundle args)
{
try {
if (getSupportFragmentManager().getBackStackEntryCount() >= 1) {
showNavigationIcon();
}
hideKeyboard();
BaseFragment fragment = createFragment(fragmentClass, args);
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
fragment.initTransactionAnimation(transaction);
String tag = getTag(fragment);
transaction.add(R.id.container, fragment, tag);
if (addToBackStack) {
transaction.addToBackStack(tag);
}
transaction.commitAllowingStateLoss();
hideLastFragment(0);
} catch (Exception e) {
Sentry.captureException(e, "Error opening fragment");
}
}
protected BaseFragment createFragment(Class<? extends BaseFragment> fragmentClass, Bundle args) throws Exception {
BaseFragment fragment = fragmentClass.newInstance();
fragment.setHasOptionsMenu(true);
fragment.setArguments(args);
fragment.setNavigationHandler(BaseFragmentNavigatorActivity.this);
fragment.setToolbar(mToolbar);
fragment.setMenuLoadService(mMenuLoaderService);
return fragment;
}
答案 0 :(得分:3)
您可以深入克隆序列化。
public static Bundle cloneThroughSerialization(@NonNull Bundle bundle) {
Parcel parcel = Parcel.obtain();
bundle.writeToParcel(parcel, 0);
Bundle clonedBundle = new Bundle();
clonedBundle.readFromParcel(parcel);
parcel.recycle();
return clonedBundle;
}
答案 1 :(得分:2)
您发布的代码似乎没问题,因此您的软件包可能会在其他位置进行修改(即使您的postDelayed延迟为0,runnable稍后会执行,可能会同时修改软件包)。尝试直接执行它而不使用postDelayed,以查看问题是否仍然存在。您可以发布更多代码,也许我们可以找出您触摸该捆绑包的其他位置。
如果没有其他帮助,您可以随时将方法从API26复制到您的代码并使用它(边缘情况 - 这似乎是一个简单的问题,所以你不应该这样做)
答案 2 :(得分:0)
无法将bundle args建模为“empty”。用片段调用Handler示例和指定的args值制作简单的代码。如果我建模错误请给我提示
public class MainActivity extends FragmentActivity {
private static final String LOG_TAG = "Main activity";
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.news_articles)
// Create an instance of ExampleFragment
final HeadlinesFragment firstFragment = new HeadlinesFragment();
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, firstFragment).commit();
long delay = 0;
final boolean addToBackStack = true;
final Bundle args666 = new Bundle();
args666.putInt("hi", 666);
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
doOpenFragment(firstFragment, addToBackStack, args666);
}
}, delay);
}
protected void doOpenFragment(HeadlinesFragment firstFragment,
final boolean addToBackStack,
final Bundle args){
int value = args.getInt("hi");
Log.d(LOG_TAG, "The value is " + value);
}
}