我正在使用the following example中的BottomNavigationDrawer
/ BottomSheetDialog
,其中BottomNavigationDrawer
在单个活动中的多个片段之间切换。
在implementing the BottomNavigationDrawer
期间,我意识到,在不使用菜单的情况下交换片段时,即单击片段中的按钮,this left the menu selection in an inconsistent state.也是在主活动中使用函数来解决触发FragmentTransaction
引起的崩溃。
public void resetNavDefault(){
if(fragment == null) {
fragment = new BottomNavigationDrawerFragment();
navigationView = fragment.getNavigationView();
} else navigationView = fragment.getNavigationView();
//navigationView.getMenu().getItem(0).setChecked(true);
Log.d(TAG, "resetNavDefault: setting check");
MenuItem item = navigationView.getMenu().getItem(0);
navigationView.getMenu().performIdentifierAction(item.getItemId(), 0);
}
我意识到这是由于getSupportFragmentManager
为空and/or the fragment not being attached引起的,而using getChildFragmentManager
不是正确的解决方案,因为我不使用嵌套片段,而是在单个活动中仅使用多个片段
我还尝试在the onDetach
is overridden to make the childFragmentManager
accessible的地方实施此解决方法。
This fix prevents the app from crashing with an NPE(由于 if (!isAdded()) return;
条件),但是启动新片段的按钮没有响应(该按钮不起作用)。
如何使用FragmentTransaction
在两个片段之间导航,而又不会导致NPE,也不会使菜单选择处于不一致的状态?
我的BottomNavigationDrawer
实现如下:
BottomNavigationDrawer
public class BottomNavigationDrawerFragment extends BottomSheetDialogFragment {
BottomNavigationDrawerFragment fragment;
public NavigationView navigationView;
ImageView close, menu;
Statuser statuser;
RevivDatabase database;
String email, fname, lname;
TextView txtUsername, txtEmail;
private static String TAG = "BottomNavDrawerFragment";
public BottomNavigationDrawerFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_bottomsheet, container, false);
txtUsername = view.findViewById(R.id.txtUsername);
txtEmail = view.findViewById(R.id.txtEmail);
navigationView = view.findViewById(R.id.navigation_view);
database = RevivDatabase.getDatabase(getActivity());
statuser = database.revivDao().getUserDetails();
fname = statuser.getFname();
lname = statuser.getLname();
email = statuser.getEmail();
txtEmail.setText(email);
txtUsername.setText(fname+" "+lname);
setRetainInstance(true);
close = view.findViewById(R.id.imgClose);
fragment = this;
close.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
fragment.dismiss();
}
});
navigationView.setItemIconTintList(null);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
@Override
public boolean onNavigationItemSelected(@NonNull MenuItem menuItem) {
menuItem.setChecked(true);
int id = menuItem.getItemId();
FragmentManager manager;
try {
manager = getActivity().getSupportFragmentManager();
} catch (NullPointerException e) {
if (!isAdded()) return false;
manager = getChildFragmentManager();
Log.e(TAG, "onNavigationItemSelected: ", e);
}
switch (id){
case R.id.app_bar_incident:
navigationView.getMenu().findItem(id).setChecked(true);
manager.beginTransaction().replace(R.id.containerFrameLayout, new FragmentRevivIncidentDashboard()).commit();
Toast.makeText(getContext(), "Request Incident", Toast.LENGTH_SHORT).show();
fragment.dismiss();
break;
case R.id.app_bar_housecall:
navigationView.getMenu().findItem(id).setChecked(true);
manager.beginTransaction().replace(R.id.containerFrameLayout, new FragmentRevivHousecallDashboard()).commit();
fragment.dismiss();
Toast.makeText(getContext(), "Request Housecall", Toast.LENGTH_SHORT).show();
break;
case R.id.settings:
navigationView.getMenu().findItem(id).setChecked(true);
manager.beginTransaction().replace(R.id.containerFrameLayout, new FragmentRevivSettingsMain()).commit();
Toast.makeText(getActivity().getApplicationContext(), "Settings", Toast.LENGTH_SHORT).show();
fragment.dismiss();
break;
}
return true;
}
});
return view;
}
@Override
public void onDetach() {
super.onDetach();
try {
Field childFragmentManager = Fragment.class.getDeclaredField("mChildFragmentManager");
childFragmentManager.setAccessible(true);
childFragmentManager.set(this, null);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public NavigationView getNavigationView() {
return navigationView;
}
}
我的错误消息
09-13 00:26:32.996 28025-28025 / com.package.name E / AndroidRuntime: 致命异常:主要 流程:com.package.name,PID:28025 java.lang.IllegalStateException:片段尚未附加。 在android.support.v4.app.Fragment.instantiateChildFragmentManager(Fragment.java:2386) 在android.support.v4.app.Fragment.getChildFragmentManager(Fragment.java:842) 在com.package.name.Fragments.BottomNavigationDrawerFragment $ 2.onNavigationItemSelected(BottomNavigationDrawerFragment.java:108) 在android.support.design.widget.NavigationView $ 1.onMenuItemSelected(NavigationView.java:170) 在android.support.v7.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:840) 在android.support.v7.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:158) 在android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:991) 在android.support.v7.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:981) 在android.support.v7.view.menu.MenuBuilder.performIdentifierAction(MenuBuilder.java:977) 在com.package.name.Reviv.resetNavDefault(Reviv.java:644) 在com.package.name.Fragments.FragmentRevivSettingsMain $ 1.onClick(FragmentRevivSettingsMain.java:77) 在android.view.View.performClick(View.java:6303) 在android.view.View $ PerformClick.run(View.java:24828) 在android.os.Handler.handleCallback(Handler.java:789) 在android.os.Handler.dispatchMessage(Handler.java:98) 在android.os.Looper.loop(Looper.java:164) 在android.app.ActivityThread.main(ActivityThread.java:6798) 在java.lang.reflect.Method.invoke(本机方法) 在com.android.internal.os.Zygote $ MethodAndArgsCaller.run(Zygote.java:240) 在com.android.internal.os.ZygoteInit.main(ZygoteInit.java:767)
答案 0 :(得分:1)
首先像在page中那样在MainActivity中实现按钮单击事件。然后,假设您在MainActivity中拥有BottomNavigationDrawerFragment实例,只需单击该实例即可获取视图,并在单击按钮时通过该视图进行导航菜单的setSelection调用。确保在调用bottomNavDrawerFragment.show(..)之后通过实例获取视图。否则,您将收到NPE错误。