我很難理解我做錯了什么,所以我希望你能幫助我。
語境 :
我正在使用 Android Studio 構建一個 Android 應用程式來控制和監控我家中的物聯網設備。我從導航抽屜活動示例開始,所以我有 3 個片段和一個導航抽屜:
- 主頁片段(“Accueil”):第一個片段出現,帶有兩個測驗按鈕以創建通知
- 運動片段(“攝像機監控”):顯示攝像機流的 web 視圖的片段
- 儀表板片段(“Tableau de bord”):顯示另一個 web 視圖的片段
導航抽屜
主頁片段
我目前正在處理一個通知,它將我的應用程式直接打開到 Motion 片段中。為此,我在通知發送的pendingIntent 中使用了一個額外的。根據它的值,在 MainActivity 的onCreate函式中,navController 被強制顯示請求的片段。就我而言,我希望通知顯示運動片段(“監控攝像機”)。
通知
Intent intent = getIntent();
String fragmentName = intent.getStringExtra(FRAGMENTNAME);
if (fragmentName == null) fragmentName = "";
switch (fragmentName) {
case "motion":
navController.navigate(R.id.nav_motion);
break;
case "dashboard":
navController.navigate(R.id.nav_dashboard);
break;
case "home":
default:
navController.navigate(R.id.nav_home);
break;
}
然后,測驗:我打開我的應用程式,單擊測驗按鈕“按鈕 1”以顯示通知,關閉我的應用程式,單擊通知,然后 Bingo!Motion 片段首先打開!這作業得很好......至少我是這么認為的。
問題:
通過這樣做,當應用程式從通知中打開時,我得到一個奇怪的行為:我無法訪問 Home 片段。
在導航抽屜中,單擊“Accueil”選單打開 Home 片段會打開 Motion 片段(“Camera de monitoring”)。要查看 Home 片段,我需要退出應用程式并再次打開它。
我猜測單擊導航抽屜上的“Accueil”按鈕以顯示 Home 片段會重置 MainActivity 并呼叫onCreate函式,但這對我來說沒有意義,因為此函式是創建應用程式時的第一個回呼并且之后不會被呼叫,是嗎?有沒有人知道真正發生了什么以及如何獲得想要的行為?
編輯:
經過一些除錯,使用通知作為指示器,我發現 MainActivity 的 onCreate 函式在啟動時只被呼叫一次。此外,當抽屜式導航處于其“怪異行為”狀態時,單擊“回傳”導航按鈕會帶回 Home 片段并糾正抽屜式導航的“怪異行為”。
發生的事情是我用來更改第一個片段的功能是導航控制器的“導航”功能。它在記憶體中保存了我從 Home 片段(真正要顯示的第一個片段)導航到 Motion 片段。因此,只要我不按“回傳”按鈕回傳導航堆疊,它就會在記憶體中保存,當我單擊主頁片段時,
我需要找到一種方法來洗掉該導航歷史記錄,或者找到另一種方法在開頭顯示 Motion 片段。
完整檔案來源:
MainActivity.java
public class MainActivity extends AppCompatActivity {
public static final String FRAGMENTNAME = "com.mrxana91dev.maisonpaul.fragmentstartname";
public NotificationManagerCompat notificationManagerCompat;
private AppBarConfiguration mAppBarConfiguration;
private ActivityMainBinding binding;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
binding = ActivityMainBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
setSupportActionBar(binding.appBarMain.toolbar);
binding.appBarMain.fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
DrawerLayout drawer = binding.drawerLayout;
NavigationView navigationView = binding.navView;
// 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_motion, R.id.nav_dashboard)
.setOpenableLayout(drawer)
.build();
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
NavigationUI.setupActionBarWithNavController(this, navController, mAppBarConfiguration);
NavigationUI.setupWithNavController(navigationView, navController);
this.notificationManagerCompat = NotificationManagerCompat.from(this);
// ADDED CODE TO CHANGE FIRST FRAGMENT DEPENDING ON FRAGMENTNAME EXTRA
Intent intent = getIntent();
String fragmentName = intent.getStringExtra(FRAGMENTNAME);
if (fragmentName == null) fragmentName = "";
switch (fragmentName) {
case "motion":
navController.navigate(R.id.nav_motion);
break;
case "dashboard":
navController.navigate(R.id.nav_dashboard);
break;
case "home":
default:
navController.navigate(R.id.nav_home);
break;
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onSupportNavigateUp() {
NavController navController = Navigation.findNavController(this, R.id.nav_host_fragment_content_main);
return NavigationUI.navigateUp(navController, mAppBarConfiguration)
|| super.onSupportNavigateUp();
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.action_settings:
Intent intent = new Intent(this, SettingsActivity.class);
startActivity(intent);
return true;
default:
return super.onOptionsItemSelected(item);
}
}
}
HomeFragment.java
public class HomeFragment extends Fragment {
public static final String EXTRA_FRAGMENT = "com.mrxana91dev.maisonpaul.fragmentstartname";
private FragmentHomeBinding binding;
public View onCreateView(@NonNull LayoutInflater inflater,
ViewGroup container, Bundle savedInstanceState) {
HomeViewModel homeViewModel =
new ViewModelProvider(this).get(HomeViewModel.class);
binding = FragmentHomeBinding.inflate(inflater, container, false);
View root = binding.getRoot();
final TextView textView = binding.textHome;
final TextView textView2 = binding.textView2;
homeViewModel.getText().observe(getViewLifecycleOwner(), textView::setText);
homeViewModel.getText2().observe(getViewLifecycleOwner(), textView2::setText);
final Button testButton1 = binding.testButton1;
final Button testButton2 = binding.testButton2;
testButton1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sendOnChannel1();
}
});
testButton2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
sendOnChannel2();
}
});
return root;
}
@Override
public void onDestroyView() {
super.onDestroyView();
binding = null;
}
private void sendOnChannel1() {
String title = "Maison Paul - Test notification";
String message = "Mouvement repéré !";
MainActivity mainActivity = (MainActivity) getActivity();
Intent intent = new Intent(mainActivity, MainActivity.class);
intent.putExtra(EXTRA_FRAGMENT, "motion");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
PendingIntent pendingIntent = PendingIntent.getActivity(mainActivity, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_MUTABLE);
Notification notification = new NotificationCompat.Builder(mainActivity, NotificationApp.CHANNEL_1_ID)
.setSmallIcon(R.drawable.ic_baseline_home_24)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setCategory(NotificationCompat.CATEGORY_MESSAGE)
.setContentIntent(pendingIntent)
.setAutoCancel(true)
.build();
int notificationId = 1;
mainActivity.notificationManagerCompat.notify(notificationId, notification);
}
private void sendOnChannel2() {
String title = "Maison Paul - Test notification";
String message = "Notification from channel 2 !";
MainActivity mainActivity = (MainActivity) getActivity();
Notification notification = new NotificationCompat.Builder(mainActivity, NotificationApp.CHANNEL_2_ID)
.setSmallIcon(R.drawable.ic_menu_camera)
.setContentTitle(title)
.setContentText(message)
.setPriority(NotificationCompat.PRIORITY_LOW)
.setCategory(NotificationCompat.CATEGORY_PROMO) // Promotion.
.build();
int notificationId = 2;
mainActivity.notificationManagerCompat.notify(notificationId, notification);
}
}
uj5u.com熱心網友回復:
好吧!我想到了。
我必須通過創建兩個操作來更改導航選單 (mobile_navigation.xml) 中的一些內容:
- 從 Home 片段導航到 Motion 片段的一種
- 從 Home 片段導航到 Dashboard 片段
的操作 這兩個操作中的每一個都使用 popUpTo 和 popUpToInclusive 進行設定。
mobile_navigation.xml(摘錄)
<action
android:id="@ id/action_nav_home_to_nav_dashboard"
app:destination="@id/nav_dashboard"
app:launchSingleTop="false"
app:popUpTo="@id/nav_home"
app:popUpToInclusive="true" />
然后,我沒有直接使用導航片段的 id 作為“導航”函式的引數,而是使用相應的操作。
MainActivity.java - onCreate(提取)
Intent intent = getIntent();
String fragmentName = intent.getStringExtra(FRAGMENTNAME);
if (fragmentName == null) fragmentName = "";
switch (fragmentName) {
case "motion":
navController.navigate(R.id.action_nav_home_to_nav_motion);
break;
case "dashboard":
navController.navigate(R.id.action_nav_home_to_nav_dashboard);
break;
case "home":
default:
// No action needed requesting the Home fragment as it's already the starting fragment
break;
}
在所有這些更改之后,單擊通知仍會按預期顯示 Motion 片段,并且單擊導航抽屜中的“Accueil”按鈕會按需要顯示 Home 片段。
解決了!
轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/513348.html
上一篇:NativeChildView不占FrameLayout的全高和全寬
下一篇:洗掉帶有片段的底部導航視圖
