Android底部导航切换至SAVED项后卡顿无法切换其他菜单
Android底部导航栏切换至SAVED项后卡顿无法切换问题
我的Android应用底部导航栏包含HOME、APPLICATIONS、SAVED、INFO四个菜单项,其中HOME、APPLICATIONS和INFO项切换正常,但切换至SAVED项后,底部导航栏出现卡顿,无法再切换到其他菜单项。
相关代码
SavedFragment
public class SavedFragment extends Fragment { private FragmentSavedBinding binding; public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentSavedBinding.inflate(inflater, container, false); View root = binding.getRoot(); ListView fileNameList = root.findViewById(R.id.listViewFiles); ArrayList<String> filenames = new ArrayList<>(); File directory = new File(getActivity().getExternalFilesDir(null), ""); File[] files = directory.listFiles((dir, name) -> name.toLowerCase().endsWith(".xls")); for (int i = 0; i < files.length; i++) { String file_name = files[i].getName(); filenames.add(file_name); } ArrayAdapter<String> arrayAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, filenames); fileNameList.setAdapter(arrayAdapter); return root; } @Override public void onActivityCreated(@Nullable Bundle savedInstanceState) { super.onActivityCreated(savedInstanceState); // TODO: Use the ViewModel } }
MainActivity
public class MainActivity extends AppCompatActivity { private ActivityMainBinding binding; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); binding = ActivityMainBinding.inflate(getLayoutInflater()); setContentView(binding.getRoot()); BottomNavigationView navView = findViewById(R.id.nav_view); AppBarConfiguration appBarConfiguration = new AppBarConfiguration.Builder( R.id.navigation_home, R.id.navigation_applications, R.id.navigation_saved, R.id.navigation_info) .build(); NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_activity_main); NavigationUI.setupActionBarWithNavController(this, navController, appBarConfiguration); NavigationUI.setupWithNavController(binding.navView, navController); } }
bottom_nav_menu.xml
<menu xmlns:android="http://schemas.android.com/apk/res/android"> <item android:id="@+id/navigation_home" android:icon="@drawable/ic_home_black_24dp" android:title="@string/title_home" /> <item android:id="@+id/navigation_applications" android:icon="@drawable/ic_dashboard_black_24dp" android:title="@string/title_applications" /> <item android:id="@+id/placeholder" android:title="" /> <item android:id="@+id/navigation_saved" android:icon="@drawable/baseline_save_alt_24" android:title="@string/title_saved" /> <item android:id="@+id/navigation_info" android:icon="@drawable/baseline_info_24" android:title="@string/title_info" /> </menu>
mobile_navigation.xml
<navigation xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/mobile_navigation" app:startDestination="@+id/navigation_home"> <fragment android:id="@+id/navigation_home" android:name="com.cremcash.eloan.ui.home.HomeFragment" android:label="@string/title_home" tools:layout="@layout/fragment_home" /> <fragment android:id="@+id/navigation_applications" android:name="com.cremcash.eloan.ui.applications.ApplicationsFragment" android:label="@string/title_applications" tools:layout="@layout/fragment_applications" /> <fragment android:id="@+id/navigation_saved" android:name="com.cremcash.eloan.ui.saved.SavedFragment" android:label="@string/title_saved" tools:layout="@layout/fragment_saved" /> <fragment android:id="@+id/navigation_info" android:name="com.cremcash.eloan.ui.info.InfoFragment" android:label="@string/logout" tools:layout="@layout/fragment_info" /> </navigation>
问题原因
- 主线程执行耗时IO操作:SavedFragment的
onCreateView中直接进行文件目录遍历和读取操作,这是耗时的IO任务,会阻塞主线程,导致UI卡顿,底部导航栏的点击事件无法被及时处理。 - 空指针隐患:
directory.listFiles()可能返回null(如目录不存在、无读取权限),此时直接访问files.length会触发空指针异常,导致Fragment加载失败,进而影响导航功能。
解决方案
1. 将文件操作移至后台线程
使用AsyncTask将文件读取任务放到子线程执行,避免阻塞主线程:
public class SavedFragment extends Fragment { private FragmentSavedBinding binding; private ArrayAdapter<String> arrayAdapter; private ArrayList<String> filenames = new ArrayList<>(); @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { binding = FragmentSavedBinding.inflate(inflater, container, false); View root = binding.getRoot(); ListView fileNameList = root.findViewById(R.id.listViewFiles); arrayAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_list_item_1, filenames); fileNameList.setAdapter(arrayAdapter); // 启动异步任务加载文件列表 new LoadFilesTask().execute(); return root; } private class LoadFilesTask extends AsyncTask<Void, Void, ArrayList<String>> { @Override protected ArrayList<String> doInBackground(Void... voids) { ArrayList<String> result = new ArrayList<>(); File directory = new File(getActivity().getExternalFilesDir(null), ""); // 先判断目录是否存在且为目录 if (directory.exists() && directory.isDirectory()) { File[] files = directory.listFiles((dir, name) -> name.toLowerCase().endsWith(".xls")); // 处理listFiles返回null的情况 if (files != null) { for (File file : files) { result.add(file.getName()); } } } return result; } @Override protected void onPostExecute(ArrayList<String> result) { filenames.clear(); filenames.addAll(result); arrayAdapter.notifyDataSetChanged(); } } @Override public void onDestroyView() { super.onDestroyView(); binding = null; } }
2. 优化占位菜单项(可选)
底部导航菜单中的placeholder项如果仅用于布局对称,建议禁用并隐藏,避免干扰导航逻辑:
<item android:id="@+id/placeholder" android:title="" android:enabled="false" android:visible="false"/>
内容的提问来源于stack exchange,提问作者JeffyO
相关产品推荐
相关产品推荐

