当前Android开发中使用Fragment来开发页面已经成为主流做法。Fragment轻量、可控性强等优点让人感觉很香。但是Fragment也有自己的硬伤,那就是回退栈与页面参数传递。
虽然当前有例如Fragmentation这样的开源库解决了这类问题,而且这些三方开源库也经受住了时间与项目的检验。但是总让Android开发者心中觉得少了点什么(尤其是学了iOS开发之后。。。)Navigation的横空出世,让Android开发者终于看到了一线曙光。
利用Navigation的三大组件,我们可以自由控制管理fragment的切换和数据传递和回退栈,不要再想以前一样通过FragmentManager进行replace或者show了,以及事务的提交,在数据传递方面,也不会通过fragmentID和接口回调的方式进行传递,大大方便了我们的代码编写。可以说,Navigation其实就是通过编写XML文件来管理导航fragment,当然如果使用熟悉了的话,也可以在AS中直接进行拖拽的方式进行快速编写代码。
在应用中导航时,您告诉 NavController,您想沿导航图中的特定路径导航至特定目标,或直接导航至特定目标。NavController 便会在 NavHost 中显示相应目标。
导航组件提供各种其他优势,包括以下内容:
此外,您还可以使用 Android Studio 的 Navigation Editor 来查看和编辑导航图。
```java
dependencies {
def nav_version = "2.3.5"
// Java language implementation
implementation "androidx.navigation:navigation-fragment:$nav_version"
implementation "androidx.navigation:navigation-ui:$nav_version"
// Kotlin
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
// Feature module Support
implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
// Testing Navigation
androidTestImplementation "androidx.navigation:navigation-testing:$nav_version"
// Jetpack Compose Integration
implementation "androidx.navigation:navigation-compose:2.4.0-alpha03"
}
当您添加首个导航图时,Android Studio 会在 res 目录内创建一个 navigation 资源目录。该目录包含您的导航图资源文件(例如 nav_graph.xml)。
<?xml version="1.0" encoding="utf-8"?>
<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/nav_graph"
app:startDestination="@id/a_fragment"> //指定导航容器最开始显示的fragment
<fragment
android:id="@+id/a_fragment"
android:name="com.example.mynavigation.fragment.A_Fragment"
android:label="afragment"
tools:layout="@layout/afragment" >
<action
android:id="@+id/action_afragment_to_bfragment"
app:destination="@+id/bfragment" //跳转到bfragment
app:enterAnim="@anim/nav_default_enter_anim">
</action>
<action android:id="@+id/action_afragment_to_efragment"
app:destination="@+id/eragment"
app:enterAnim="@anim/nav_default_enter_anim"></action>
</fragment>
</navigation>
<?xml version="1.0" encoding="utf-8"?>
<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">
<androidx.appcompat.widget.Toolbar
.../>
<androidx.fragment.app.FragmentContainerView
android:id="@+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_graph" />
<com.google.android.material.bottomnavigation.BottomNavigationView
.../>
</androidx.constraintlayout.widget.ConstraintLayout>
请注意以下几点:
您也可以使用布局编辑器向 Activity 添加 NavHostFragment,具体操作步骤如下:
在项目文件列表中,双击 Activity 的布局 XML 文件,以在 Layout Editor 中将其打开。
在本示例中,我们来创建一个新目的地。如需使用 Navigation Editor 添加新目的地,请执行以下操作:
目的地详解
点击一个目的地以将其选中,并注意 Attributes 面板中显示的以下属性:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
app:startDestination="@id/blankFragment">
<fragment
android:id="@+id/blankFragment"
android:name="com.example.cashdog.cashdog.BlankFragment"
android:label="Blank"
tools:layout="@layout/fragment_blank" />
</navigation>
始目的地是用户打开您的应用时看到的第一个屏幕,也是用户退出您的应用时看到的最后一个屏幕。Navigation Editor 使用房子图标 表示起始目的地。
所有目的地就绪后,您便可以选择起始目的地,具体操作步骤如下:
操作是指目的地之间的逻辑连接。操作在导航图中以箭头表示。操作通常会将一个目的地连接到另一个目的地,不过您也可以创建全局操作,此类操作可让您从应用中的任意位置转到特定目的地。
借助操作,您可以表示用户在您的应用中导航时可以采取的不同路径。请注意,如需实际导航到各个目的地,您仍然需要编写代码以执行导航操作。如需了解详情,请参阅本主题后面的导航到目的地部分。
您可以使用 Navigation Editor 将两个目的地连接起来,具体操作步骤如下:
<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android"
app:startDestination="@id/a_fragment">
<fragment
android:id="@+id/a_fragment"
android:name="com.example.cashdog.cashdog.a_fragment"
android:label="afragment"
tools:layout="@layout/a_fragment" >
<action
android:id="@+id/action_a_fragment_to_b_fragment"
app:destination="@id/b_fragment" />
</fragment>
<fragment
android:id="@+id/b_fragment"
android:name="com.example.cashdog.cashdog.b_fragment"
android:label="bfragment"
tools:layout="@layout/b_fragment" />
</navigation>
public class MainActivity extends AppCompatActivity {
private BottomNavigationView buttion ;
private NavController controller;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttion = findViewById(R.id.nav_bt);
controller = Navigation.findNavController(this,R.id.navigation_host);
controller.navigate(R.id.action_to_afragment);
}
``
用bundle传递参数
```java
Bundle bundle = new Bundle();
bundle.putString("name","navigation");
Navigation.findNavController(getView()).navigate(R.id.action_afragment_to_efragment,bundle);
接收参数:
mParam1 = getArguments().getString("name");
假如通过URL访问b_fragment,需要利用deepLink标签
<fragment
android:id="@+id/b_fragment"
android:name="com.example.mynavigation.fragment.B_Fragment"
android:label="afragment"
tools:layout="@layout/bfragment" >
<deepLink app:uri="www.YourWebsite.com/{params}" />
</fragment>
与此同时,需要在AndroidMenuifest文件里加入导航图nav-graph
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.MyNavigation">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<nav-graph android:value="@navigation/nav_graph"></nav-graph>
</activity>
</application>
public class B_Fragment extends Fragment {
private static final String CHANNEL_ID = "123" ;
private int notificationId = 123;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.bfragment, container, false);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
Button button3 = view.findViewById(R.id.button3);
button3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
sendNotification();
}
});
}
private void sendNotification(){
if(getActivity() == null)
{
return;
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
{
int importance = NotificationManager.IMPORTANCE_DEFAULT;
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, "ChannelName", importance);
channel.setDescription("description");
NotificationManager notificationManager = getActivity().getSystemService(NotificationManager.class);
notificationManager.createNotificationChannel(channel);
}
NotificationCompat.Builder builder = new NotificationCompat.Builder(getActivity(), CHANNEL_ID)
.setSmallIcon(R.drawable.ic_launcher_background)
.setContentTitle("DeepLinkDemo")
.setContentText("Hello World!")
.setPriority(NotificationCompat.PRIORITY_DEFAULT)
.setContentIntent(getPendingIntent());//设置PendingIntent .setAutoCancel(true);
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(getActivity());
notificationManager.notify(notificationId, builder.build());
}
private PendingIntent getPendingIntent(){
if(getActivity() != null)
{
Bundle bundle = new Bundle();
bundle.putString("params", "from Notification");
return Navigation
.findNavController(getActivity(), R.id.button3)
.createDeepLink()
.setGraph(R.navigation.nav_graph)
.setDestination(R.id.b_fragment)
.setArguments(bundle)
.createPendingIntent();
}
return null;}
}