Android NavHost: «Место назначения навигации, соответствующее запросу NavDeepLinkRequest, не найдено в графе навигации»Android

Форум для тех, кто программирует под Android
Ответить Пред. темаСлед. тема
Anonymous
 Android NavHost: «Место назначения навигации, соответствующее запросу NavDeepLinkRequest, не найдено в графе навигации»

Сообщение Anonymous »

Вот мой соответствующий код, созданный с помощью Kotlin + Jetpack Compose:
OutlookPlannerNavHost.kt

Код: Выделить всё

/**
* Provides Navigation graph for the application.
*/
@Composable
fun OutlookPlannerNavHost(
navController: NavHostController,
modifier: Modifier = Modifier
) {
NavHost(
navController = navController,
startDestination = DestinationHome.route,
modifier = modifier
) {
/**
* Home page
*/
composable(route = DestinationHome.route) {
Home(
modifier = modifier,
pageCurrent = DestinationHome.route,
navigateToPlanMake = { navController.navigate(route = DestinationPlanMake.route) },
navigateToPlanEdit = { planId -> navController.navigate(route = "${DestinationPlanEdit.route}/${planId}") }
)
}
/**
* Make Plan page
*/
composable(route = DestinationPlanMake.route) {
PlanMake(
modifier = modifier,
pageCurrent = DestinationPlanEdit.route,
navigateBack = {
navController.popBackStack()
},
)
}
/**
* Edit Plan page
* (AKA Make Plan page with a Plan object passed)
*/
composable(
route = DestinationPlanEdit.routeWithId,
arguments = listOf(navArgument(name = DestinationPlanEdit.PLAN_ID) {
type = NavType.IntType
})
) {
Log.d("Args", it.arguments?.getInt(DestinationPlanEdit.PLAN_ID).toString())
PlanMake(
modifier = modifier,
pageCurrent = DestinationPlanEdit.route,
navigateBack = { navController.popBackStack() },
)
}
}
}
Home.kt

Код: Выделить всё

@Composable
fun Home(
modifier: Modifier = Modifier,
navigateToPlanMake: () -> Unit,
navigateToPlanEdit: (Int) ->  Unit,
pageCurrent: String,
viewModel: HomeViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
/**
* Immutable variables
*/
val homeUiState by viewModel.homeUiState.collectAsState()
val planList = homeUiState.planList

Scaffold (
floatingActionButton = {
AppFAB(
pageCurrent = pageCurrent,
onClick = navigateToPlanMake
)
},
modifier = modifier,
) {
LazyColumn (modifier = modifier.padding(it)) {
item {
ViewingArea()
}
items(items = planList) { planEntity ->
PlanCard(
planEntity = planEntity,
modifier = modifier
.padding(16.dp)
.clickable { navigateToPlanEdit(planEntity.id) }
)
}
}
}
}
NavigationDestination.kt

Код: Выделить всё

/**
* Interface to describe the navigation destinations for the app
*/
interface NavigationDestination {
/**
* Unique name to define the path for a composable
*/
val route: String

/**
* String resource id to that contains title to be displayed for the screen.
*/
val titleRes: Int
}
DestinationPlanEdit.kt

Код: Выделить всё

object DestinationPlanEdit: NavigationDestination {
override val route = R.string.route_plan_edit.toString()
override val titleRes = R.string.name_plan_edit
/**
* Additional values for routing
*/
const val PLAN_ID: String = "planId"
val routeWithId: String = "$route/${PLAN_ID}"
}
PlanMakeViewModel.kt

Код: Выделить всё

class PlanMakeViewModel(
savedStateHandle: SavedStateHandle,
private val planRepository: PlanRepository,
): ViewModel() {
/**
* Make Plan UI state
*/
var planMakeUiState by mutableStateOf(PlanMakeUiState())
private set

/**
* Initialize private values in presence of an existing Plan object
*/
init {
try {
val planId: Int = checkNotNull(savedStateHandle[DestinationPlanEdit.PLAN_ID])
viewModelScope.launch {
planMakeUiState = planRepository
.getPlanOne(planId)
.filterNotNull()
.first()
.toMakePlanUiState()
}
} catch(_: Exception) {
/**
* No Plan ID supplied
*
* Assume user is making plan, or plan is missing in database
*/
}
}

/**
* Check that no fields are empty
*/
private fun validateInput(planCheck: Plan = planMakeUiState.plan): Boolean {
return with(planCheck) {
note.isNotBlank()
}
}

/**
* Updates the [planMakeUiState] with the value provided in the argument.  This method also triggers
* a validation for input values.
*/
fun updateUiState(planUpdated: Plan) {
planMakeUiState = PlanMakeUiState(
plan = planUpdated,
fieldNotEmptyAll = validateInput(planUpdated)
)
}

/**
* Insert + Update current plan
*/
suspend fun planUpsert() {
if (validateInput()) planRepository.planUpsert(planMakeUiState.plan.toEntity())
}
}
Они взяты из моего проекта приложения Outlook Planner на GitHub
Под лицензией GPL вы можете git клонировать его на свои компьютеры и проверять самостоятельно.
Моя цель на NavHost — извлечь Plan.id из составной функции Home, а затем перенести это значение в DestinationPlanEdit.routeWithId для редактирования этого < em>Plan и сохраните его в базе данных Room.
Единственная проблема заключается в том, что он возвращает следующую ошибку:

Код: Выделить всё

FATAL EXCEPTION: main
Process: com.outlook.planner, PID: 19658
java.lang.IllegalArgumentException: Navigation destination that matches request NavDeepLinkRequest{ uri=android-app://androidx.navigation/2131689725/3 } cannot be found in the navigation graph ComposeNavGraph(0x0) startDestination={Destination(0xf08bc5ce) route=2131689704}
at androidx.navigation.NavController.navigate(NavController.kt:1819)
at androidx.navigation.NavController.navigate(NavController.kt:2225)
at androidx.navigation.NavController.navigate$default(NavController.kt:2220)
at com.outlook.planner.ui.navigation.OutlookPlannerNavHostKt$OutlookPlannerNavHost$1$1$2.invoke(OutlookPlannerNavHost.kt:38)
at com.outlook.planner.ui.navigation.OutlookPlannerNavHostKt$OutlookPlannerNavHost$1$1$2.invoke(OutlookPlannerNavHost.kt:34)
at com.outlook.planner.ui.pages.home.HomeKt$Home$2$1$1$1$1.invoke(Home.kt:52)
at com.outlook.planner.ui.pages.home.HomeKt$Home$2$1$1$1$1.invoke(Home.kt:52)
at androidx.compose.foundation.ClickablePointerInputNode$pointerInput$3.invoke-k-4lQ0M(Clickable.kt:987)
at androidx.compose.foundation.ClickablePointerInputNode$pointerInput$3.invoke(Clickable.kt:981)
Я не знаю, как это решить. Я просмотрел различные видеоуроки в Интернете (большинство из которых бесполезны, поскольку в них преподаются XML и фрагменты, а это не то, что я изучаю в Основах Android с Compose
Я спрашиваю за помощью относительно причины этой проблемы, так как я устал и не могу исправить это самостоятельно. Но мне нужна эта функция для работы.
Заранее спасибо.
РЕДАКТИРОВАТЬ
Еще несколько соответствующих файлов на случай, если клонирование проектов GitHub вам не по душе:
PlanMakeUiState.kt< /strong>

Код: Выделить всё

/**
* Data class that represents the plan UI state
*
* Uses:
* - Hold current plan
* - Check if all fields are not empty
* - To show MaterialTimePicker or not
* - To show MaterialDatePicker or not
*/
data class PlanMakeUiState(
val plan: Plan = Plan(
note = "",
year = LocalDateTime.now().year,
month = LocalDateTime.now().monthValue,
date = LocalDateTime.now().dayOfMonth,
hour = LocalDateTime.now().hour,
minute = LocalDateTime.now().minute,
),
val fieldNotEmptyAll: Boolean = false
)


MakePlan.kt[/b]

Код: Выделить всё

@Composable
fun PlanMake(
modifier: Modifier = Modifier,
pageCurrent: String,
navigateBack: () -> Unit,
context: Context = LocalContext.current,
viewModel: PlanMakeViewModel = viewModel(factory = AppViewModelProvider.Factory)
) {
/**
* Immutable values
*/
val coroutineScope = rememberCoroutineScope()

Scaffold(
floatingActionButton = {
AppFAB(
pageCurrent = pageCurrent,
onClick = {
coroutineScope.launch {
viewModel.planUpsert()
navigateBack()
}
}
)
},
modifier = modifier
) { innerPadding ->
Column(
horizontalAlignment = Alignment.CenterHorizontally,
modifier = Modifier
.padding(innerPadding)
.fillMaxWidth()
) {
ViewingArea(pageCurrent = pageCurrent)

/**
* Note of plan
*/
MakePlanBody(
modifier = modifier,
planMakeUiState = viewModel.planMakeUiState,
onPlanValueChange = viewModel::updateUiState,
context = context
)
}
}
}

/**
* References:
* https://codingwithrashid.com/how-to-add-underlined-text-in-android-jetpack-compose/
*/
@Composable
fun MakePlanBody(
modifier: Modifier = Modifier,
planMakeUiState: PlanMakeUiState,
onPlanValueChange: (Plan) -> Unit,
context: Context
) {
/**
* Encompass the Plan in the UI state to a concise pointer variable
*/
val plan: Plan = planMakeUiState.plan

/**
* Embellishment values
*/
val heightSpacer: Dp = 32.dp
val heightSpacerBetweenTextAndButton: Dp = 8.dp
val textStyle = TextStyle(textAlign = TextAlign.Left)
val sizeFontOfHeader = 16.sp
val sizeFontOfDateTimeValue = 24.sp

/**
* Logic variables
*/
var showPickerTime: Boolean by remember { mutableStateOf(false) }
var showPickerDate: Boolean by remember { mutableStateOf(false) }

/**
* Display variables
*/
var displayTime: LocalTime by remember { mutableStateOf(LocalTime.of(plan.hour, plan.minute)) }
var displayDate: LocalDate by remember { mutableStateOf(LocalDate.of(plan.year, plan.month, plan.date)) }

/**
* Field to insert a note
*/
Text(
text = "Note",
fontSize = sizeFontOfHeader
)
TextField(
value = planMakeUiState.plan.note,
onValueChange = { noteNew ->  onPlanValueChange(plan.copy(note = noteNew)) },
textStyle = textStyle,
placeholder = {
Text(
text = "Your note here",
textAlign = TextAlign.Center,
)
}
)
Spacer(modifier = Modifier.height(heightSpacer))

/**
* Field to pick a time
*/
Text(
text = stringResource(id = R.string.ask_time),
fontSize = sizeFontOfHeader
)
Spacer(modifier = Modifier.height(heightSpacerBetweenTextAndButton))
Text(
text = buildAnnotatedString {
append("On")
append(" ")
withStyle(style = SpanStyle(textDecoration = TextDecoration.Underline)) {
append(displayTime.toString())
}
},
fontSize = sizeFontOfDateTimeValue,
)
Spacer(modifier = Modifier.height(heightSpacerBetweenTextAndButton))
Button(
onClick = { showPickerTime = !showPickerTime },
) {
Text(
text = stringResource(id = R.string.set_time)
)
if(showPickerTime) {
ShowMaterialDateTimePicker(
context = context,
typeReturn = TYPE_TIME,
onDateTimeSet = {
newTime -> onPlanValueChange(plan.copy(hour = newTime.hour, minute = newTime.minute))
}
)
showPickerTime = !showPickerTime
}
// Update the time to show on UI screen
displayTime = LocalTime.of(plan.hour, plan.minute)
}
Spacer(modifier = Modifier.height(heightSpacer))

/**
* Field to pick a date
*/
Text(
text = stringResource(id = R.string.ask_date),
fontSize = sizeFontOfHeader
)
Spacer(modifier = Modifier.height(heightSpacerBetweenTextAndButton))
Text(
text = when(displayDate) {
LocalDate.now() -> "Today!"
LocalDate.now().plusDays(1) -> "Tomorrow!"
else -> "${displayDate.dayOfMonth} ${displayDate.month} ${displayDate.year}"
},
fontSize = sizeFontOfDateTimeValue,
)
Spacer(modifier = Modifier.height(heightSpacerBetweenTextAndButton))
Button(
onClick = { showPickerDate = !showPickerDate },
) {
Text(
text = stringResource(id = R.string.set_date)
)
if(showPickerDate) {
ShowMaterialDateTimePicker(
typeReturn = TYPE_DATE,
onDateTimeSet = {newDate -> onPlanValueChange(plan.copy(date = newDate.dayOfMonth, month = newDate.monthValue, year = newDate.year))
}
)
showPickerDate = !showPickerDate
}
// Update the [displayDate] to show on UI screen display
displayDate = LocalDate.of(plan.year, plan.month, plan.date)
}
}

@Composable
fun ShowMaterialDateTimePicker(
context: Context? = null,
typeReturn: String,
onDateTimeSet: (LocalDateTime) -> Unit
) {
/**
* Shared variables among the dialogs
*/
var pickedDateTime: LocalDateTime = LocalDateTime.now()

/**
* Check if user wants date or time
*/
when(typeReturn) {
/**
* RETURN:
* Time in Hours & Minutes
*
* Build the MaterialTimePicker Dialog
*/
TYPE_TIME ->  {
val pickerTime = PickerTime(
modeInput = MaterialTimePicker.INPUT_MODE_CLOCK,
title = "Set a Time",
setClockFormat = is24HourFormat(context)
).dialog

/**
* Show it
*/
pickerTime.show(
getActivity().supportFragmentManager,
DestinationPlanMake.route
)
/**
* Save its values
*/
pickerTime.addOnPositiveButtonClickListener {
/**
* Convert the chosen time to Java's new API called "LocalDateTime"
* then pass two arguments to it to be made:
* - date = LocalDateTime.now().toLocalDate()
* - time = Picked time of user
*/
pickedDateTime = LocalDateTime.of(
LocalDateTime.now().toLocalDate(),
LocalTime.of(pickerTime.hour, pickerTime.minute)
)
/**
* And then we return that value
*/
Log.d("ADebug", "Picked time is now ${pickedDateTime.toLocalTime()}")
onDateTimeSet(pickedDateTime)
}
}
/**
* RETURN:
* Date in Year, Month, Date
*
* Build the MaterialDatePicker Dialog
*/
TYPE_DATE -> {
val pickerDate = PickerDate(title = stringResource(id = R.string.set_date)).dialog

/**
* Show it
*/
pickerDate.show(
getActivity().supportFragmentManager,
DestinationPlanMake.route
)
/**
* Save its values
*/
pickerDate.addOnPositiveButtonClickListener { dateInLong ->
/**
* Convert the chosen date to Java's new API called "LocalDateTime"
* then pass two arguments to it to be made:
* - date = Conversion of user's picked date from long (default type) to a date
* - time = Picked time of user
*
* NOTE:
* By default, this returns the date yesterday, so
* use plusDays() or UTC timezone to correct that
*
* - https://stackoverflow.com/a/7672633
*/
//                pickedDateTime = LocalDateTime.ofInstant(Instant.ofEpochMilli(dateInLong), TimeZone.getDefault().toZoneId())
pickedDateTime = Instant.ofEpochMilli(dateInLong).atZone(ZoneId.of("UTC")).toLocalDateTime()

/**
* And then we return that value
*/
Log.d("ADebug", "What is ${pickedDateTime.dayOfMonth} ${pickedDateTime.monthValue} ${pickedDateTime.year} to you?")
Log.d("ADebug", "Correct date should be ${LocalDateTime.now().toLocalDate()} to you?")
Log.d("ADebug", "Timezone is ${TimeZone.getDefault()}\n vs. ${TimeZone.getTimeZone("UTC")} to you?")
//                Log.d("ADebug", "What is $selectedDate to you?")
onDateTimeSet(pickedDateTime)
}
}
else -> {
/**
* Neither was specified,
* so return a generic answer: Today
*/
onDateTimeSet(pickedDateTime)
}
}
}



Подробнее здесь: https://stackoverflow.com/questions/783 ... inkrequest
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «Android»