1、关于单Activity架构的好处
对于Activity之间的跳转,往往是通过startActivity来完成跳转,在当前应用进程中,有一个Activity A,它想要跳转到Activity B,其中内部就涉及到了binder机制 + AMS,AMS属于系统进程,也就是说在Activity跳转的时候,在内部其实涉及到了进程间的通信。
对于Binder机制来说,它的显著特点就是会验证身份,这也是相较于Socket通信的优势,它会验证当前要跳转过去的Activity B是不是真的Activity,如果验证是真的,那么就会将B显示出来。
Activity之间的切换浪费那么多的资源,而Fragment就不会;对于Fragment来说,它的内存开销很小,而且Fragment之间不能直接通信,因此耦合性也很低,所以单Activity和多Fragment架构无异于是更好的架构选择,切换界面顺滑。
2、Fragment的切换
既然选择单Activity架构,那么势必就会进行Fragment之间的切换、回退等操作,像Activity这种切换回退操作很简单,但是Fragment之间就不是这个简单的切换操作就能完成。
在之前的架构中,通常使用MainActivity作为容器,保存几个Fragment界面,这样的Fragment界面之间的切换非常简单,但是如果在Fragment界面中,切换到另一个Fragment界面,就涉及到回退栈的问题,在Activity中有任务栈的概念,对于Fragment的回退栈,后面会简单介绍。
3、单Activity架构的实现
(1)在MainActivity中,添加ToolBar + NaviHostFragment + BottomNavigationView,详细的内容见《实现导航栏的几种方式》,其中有实现的详细讲解。
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.bottomnavigation.BottomNavigationView
android:id="@+id/bottomnavigationview"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="@android:color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:menu="@menu/nav_menu" />
<fragment
android:id="@+id/fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
app:defaultNavHost="true"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/toolbar"
app:layout_constraintBottom_toTopOf="@id/bottomnavigationview"
app:navGraph="@navigation/nav" />
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="?attr/colorPrimary"
android:minHeight="?attr/actionBarSize"
android:theme="?attr/actionBarTheme"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
(2)将所有需要显示的Fragment全部加入NavHost中(注意是全部,不只有主界面显示的4个Fragment),在主界面中配置导航。
bottomnavigationview = findViewById(R.id.bottomnavigationview);
toolbar = findViewById(R.id.toolbar);
//随着底部导航按钮点击移动
NavController controller = Navigation.findNavController(this, R.id.fragment);
NavigationUI.setupWithNavController(bottomnavigationview,controller);
//消除back按键,随着点击改变ToolBar显示
AppBarConfiguration configuration = new AppBarConfiguration.Builder(bottomnavigationview.getMenu()).build();
NavigationUI.setupWithNavController(toolbar,controller,configuration);
(3)Fragment页面跳转
当点击Fragment界面中的按钮,跳转到另一个Fragment界面时,需要在nav中来设置方向。
<fragment
android:id="@+id/shopFragment"
android:name="com.example.singleactivity.fragment.ShopFragment"
android:label="ShopFragment" >
<action
android:id="@+id/action_shopFragment_to_fragment1"
app:destination="@id/fragment1" />
</fragment>
这个时候,在XML文件中,出现action
属性,id代表方向,从shopFragment到fragment1,destination
代表目的地,为fragment1。
当点击跳转的时候,这个action就起到作用了。
//点击进入下一界面
btn_enter1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.findNavController(v)
.navigate(R.id.action_shopFragment_to_fragment1);
}
});
方式1:通过findNavController
,找到对应的导航容器,调用navigate
方法,传入对应的action
,便可跳转到对应的Fragment
。
btn_enter1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Navigation.createNavigateOnClickListener(R.id.action_shopFragment_to_fragment1).onClick(v);
}
});
方式2:通过createNavigateOnClickListener
,传入对应的action,调用onClick
方法,同样可以响应点击事件,跳转到对用的Fragment
。