点击通知启动App崩溃:Fragment加载失败问题求助
我给App实现了新的事件通知功能,但点击通知启动App时发生崩溃,报错信息如下:
Process: it.breakingbad.crimegoaway, PID: 13239
java.lang.RuntimeException: Unable to start activity ComponentInfo{it.breakingbad.crimegoaway/it.breakingbad.crimegoaway.NavBarActivity}: android.view.InflateException: Binary XML file line #15 in it.breakingbad.crimegoaway:layout/activity_nav_bar: Binary XML file line #19 in it.breakingbad.crimegoaway:layout/content_nav_bar: Error inflating class fragment
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3520)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3692)
at android.app.ActivityThread.handleRelaunchActivityInner(ActivityThread.java:5580)
at android.app.ActivityThread.handleRelaunchActivity(ActivityThread.java:5486)
at android.app.servertransaction.ActivityRelaunchItem.execute(ActivityRelaunchItem.java:69)
at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
我怀疑问题出在NavBarActivity的onCreate方法中ActivityNavBarBinding.inflate(getLayoutInflater());这一行,以下是相关代码:
NavBarActivity的onCreate逻辑
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO); try { binding = ActivityNavBarBinding.inflate(getLayoutInflater()); // ... rest of body of onCreateView() ... } catch (Exception e) { Log.e("TAG", "onCreateView", e); } setContentView(binding.getRoot()); setSupportActionBar(binding.appBarNavBar.toolbar); DrawerLayout drawer = binding.drawerLayout; NavigationView navigationView = binding.navView; View headerView = navigationView.getHeaderView(0); // Get Username and Email TextViews TextView userName = headerView.findViewById(R.id.nav_username); TextView userEmail = headerView.findViewById(R.id.nav_email); // set user name and email userName.setText("Username"); Users.writeUsernameNavBar(userName); userEmail.setText(Users.getCurrentUser().getCurrentUser().getEmail()); // Passing each menu ID as a set of Ids because each // menu should be considered as top level destinations. mAppBarConfiguration = new AppBarConfiguration.Builder( R.id.nav_home, R.id.nav_add_alert, R.id.nav_profile, R.id.nav_view_alerts, R.id.nav_my_alerts, R.id.nav_exit) .setOpenableLayout(drawer) .build(); NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_nav_bar); NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration); NavigationUI.setupWithNavController(navigationView, navController); //work manager declaration if not present if(getIntent().getExtras() == null) { WorkManager.getInstance(getApplicationContext()).cancelAllWorkByTag(TAG_ALERTS); WorkRequest workAlertRequest = new PeriodicWorkRequest.Builder(AlertCheckerWorker.class, 4, TimeUnit.MINUTES) /*.setInitialDelay(3, TimeUnit.MINUTES)*/ .addTag(TAG_ALERTS).build(); WorkManager.getInstance(getApplicationContext()).enqueue(workAlertRequest); WorkManager.getInstance(getApplicationContext()).cancelAllWorkByTag(TAG_COMMENTS); WorkRequest workCommentRequest = new PeriodicWorkRequest.Builder(CommentCheckerWorker.class, 4, TimeUnit.MINUTES) /*.setInitialDelay(3, TimeUnit.MINUTES)*/ .addTag(TAG_COMMENTS).build(); WorkManager.getInstance(getApplicationContext()).enqueue(workCommentRequest); } //used for notification "re-routing" if(getIntent().getExtras() != null){ Bundle bundle = getIntent().getExtras(); if(bundle.getParcelable("alert") != null) { Alert alert = bundle.getParcelable("alert"); DetailAlertFragment fragment_alert = new DetailAlertFragment(); fragment_alert.setArguments(bundle); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.add(R.id.nav_host_fragment_content_nav_bar, fragment_alert); transaction.commit(); } } }
通知创建代码
Intent resultIntent = new Intent(getApplicationContext(), NavBarActivity.class); Bundle bundle = new Bundle(); bundle.putParcelable("alert", tempAlert); resultIntent.putExtras(bundle); //resultIntent.putExtra("alert", tempAlert); Log.d("AlertCheckerWorker", "doWork: " + tempAlert.toString()); // Create the TaskStackBuilder and add the intent, which inflates the back stack TaskStackBuilder stackBuilder = TaskStackBuilder.create(getApplicationContext()); stackBuilder.addNextIntentWithParentStack(resultIntent); // Get the PendingIntent containing the entire back stack int notificationId = (int) (System.currentTimeMillis() + new Random().nextInt()); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(notificationId, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT); Notification notification = new NotificationCompat.Builder(getApplicationContext(), CHANNEL_ID) .setSmallIcon(R.drawable.category_crime) .setContentTitle("Alert Title: " + tempAlert.getTitle()) .setContentText("Description: " + tempAlert.getDescription()) .setContentIntent(resultPendingIntent) .setAutoCancel(true) .setDefaults(Notification.DEFAULT_ALL) .setPriority(NotificationCompat.PRIORITY_HIGH) .build(); notificationManager.notify(notificationId, notification);
DetailAlertFragment接收数据代码
alert = getArguments().getParcelable("alert"); //GraphicTools.showToast(getContext(),alert.toString()); alertTitleTextView.setText(alert.getTitle()); alertAddCommentImageButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if(alertAddCommentEditText.getText().toString().length()>0){ Comment comment=new Comment(alertAddCommentEditText.getText().toString(), Timestamp.now(), FirebaseAuth.getInstance().getCurrentUser().getUid()); Comments.addCommentInFirestore(alert.getDocumentId(),comment); alertAddCommentEditText.setText(""); }else { alertAddCommentEditText.setError("Add a comment"); } } }); alertDescriptionTextView.setText(alert.getDescription());

核心问题分析
崩溃的直接原因是尝试向导航组件的宿主容器(R.id.nav_host_fragment_content_nav_bar)添加Fragment,该容器是Navigation Component专用的,只能由NavController管理Fragment切换,手动调用FragmentTransaction.add()会破坏导航栈结构,触发布局膨胀异常。你怀疑的ActivityNavBarBinding.inflate()并不是问题根源,真正触发点是通知跳转后的Fragment事务代码。
修复步骤
移除手动添加Fragment的代码
删除NavBarActivity中通知处理块里的以下代码:DetailAlertFragment fragment_alert = new DetailAlertFragment(); fragment_alert.setArguments(bundle); FragmentTransaction transaction = getSupportFragmentManager().beginTransaction(); transaction.add(R.id.nav_host_fragment_content_nav_bar, fragment_alert); transaction.commit();使用Navigation Component深层链接跳转
第一步:给
DetailAlertFragment配置深层链接
打开导航XML文件(如nav_graph.xml),给目标Fragment添加深层链接配置:<fragment android:id="@+id/detailAlertFragment" android:name="it.breakingbad.crimegoaway.DetailAlertFragment" android:label="DetailAlertFragment"> <argument android:name="alert" app:argType="it.breakingbad.crimegoaway.Alert" /> <deepLink android:id="@+id/deepLink_detailAlert" app:uri="app://crimegoaway/alert" /> </fragment>第二步:修改通知Intent为深层链接形式
替换通知创建代码中的Intent部分:// 创建深层链接Intent Intent resultIntent = new Intent(getApplicationContext(), NavBarActivity.class); // 传递Parcelable参数 resultIntent.putExtra("alert", tempAlert); // 标记为导航跳转Intent resultIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP); // 保持TaskStackBuilder和PendingIntent代码不变 TaskStackBuilder stackBuilder = TaskStackBuilder.create(getApplicationContext()); stackBuilder.addNextIntentWithParentStack(resultIntent); int notificationId = (int) (System.currentTimeMillis() + new Random().nextInt()); PendingIntent resultPendingIntent = stackBuilder.getPendingIntent(notificationId, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_ONE_SHOT);第三步:通过NavController处理跳转
在NavBarActivity的通知处理块中,改用NavController跳转:if(getIntent().getExtras() != null){ Bundle bundle = getIntent().getExtras(); if(bundle.getParcelable("alert") != null) { NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_nav_bar); // 跳转到DetailAlertFragment并传递参数 navController.navigate(R.id.detailAlertFragment, bundle); } }第四步:Fragment中安全接收参数
推荐使用Safe Args(需在gradle中配置),也可以保留原代码但增加判空:// Safe Args方式(推荐) DetailAlertFragmentArgs args = DetailAlertFragmentArgs.fromBundle(getArguments()); Alert alert = args.getAlert(); // 普通方式(增加判空) Alert alert = getArguments().getParcelable("alert"); if (alert == null) { getActivity().onBackPressed(); return; } alertTitleTextView.setText(alert.getTitle()); // ... 其他逻辑
额外优化
现有代码中通过getIntent().getExtras() != null跳过WorkManager初始化的逻辑可以保留,避免App后台唤醒时重复创建任务。
修复原理
Navigation Component的宿主容器由框架统一管理导航栈,手动操作Fragment事务会导致框架状态混乱,引发布局异常。使用NavController跳转符合组件化规范,框架会自动处理Fragment的切换和栈管理,同时保证参数传递的安全性。
内容的提问来源于stack exchange,提问作者STEFANO MASIERO

