建设一个网站需要什么安全设备,网站要怎样做才能获得市场份额,淘宝客做网站教程,电子商务网站系统规划报告我在“Now In Android”中学到的 9 件事 Now in Android是一款功能齐全的 Android 应用程序#xff0c;完全使用 Kotlin 和 Jetpack Compose 构建。它遵循 Android 设计和开发最佳实践#xff0c;旨在为开发人员提供有用的参考。 https://github.com/android/nowinandroid UI…我在“Now In Android”中学到的 9 件事 Now in Android是一款功能齐全的 Android 应用程序完全使用 Kotlin 和 Jetpack Compose 构建。它遵循 Android 设计和开发最佳实践旨在为开发人员提供有用的参考。 https://github.com/android/nowinandroid UI 状态类
sealed interface InterestsUiState {object Loading : InterestsUiStatedata class Interests(val authors: ListFollowableAuthor,val topics: ListFollowableTopic) : InterestsUiStateobject Empty : InterestsUiState
}此类旨在保存屏幕上显示的流数据这些数据将随时间或事件发生变化例如调用 API 显示动作电影的流将需要视图来显示加载屏幕以防请求花费太长时间在显示查询结果之前如果发现异常则显示错误屏幕。
在发现这一点之前我是这样管理视图模型中屏幕上显示的流数据的
var authors: LiveDataListFollowableAuthor MutableLiveData(emptyList())
var topics: LiveDataListFollowableTopic MutableLiveData(emptyList())val isLoading MutableLiveData(true)val isEmpty: LiveDataBoolean authors.switchMap { authors -topics.map { topics -topics.isEmpty() authors.isEmpty()}
}init {viewModelScope.launch {authors authorsRepository.getAuthorsStream()topics topicsRepository.getTopicsStream()}.invokeOnCompletion {isLoading.value false}
}现在代码看起来像这样
val uiState combine(authorsRepository.getAuthorsStream(),topicsRepository.getTopicsStream(),
) { availableAuthors, availableTopics -InterestsUiState.Interests(authors availableAuthors,topics availableTopics)
}.stateIn(scope viewModelScope,started SharingStarted.WhileSubscribed(5_000),initialValue InterestsUiState.Loading
)在这个例子中我从 LiveData 切换到 StateFlow但实际上使用“asLiveData()”和“asFlow()”方法仍然很容易互换 State holder UI State https://developer.android.com/topic/architecture/ui-layer/state-production#stream-apis 使用构造函数引用转换流
val myStream combine(followedAuthorIdsStream,authorStream,::Pair
)而不是“手动”映射它…
val myStream
combine(followedAuthorIdsStream,authorStream,
) { followedAuthorIds, author - Pair(followedAuthorIds, author)
}“::Class”被称为构造函数引用。构造函数可以像方法和属性一样被引用。您可以在程序需要函数类型对象的任何地方使用它们该对象采用与构造函数相同的参数并返回适当类型的对象。
轻松将其映射到密封接口结果中
return combine(followedAuthorIdsStream,authorStream,::Pair
).asResult() // - The change is here !因为我们之前将我们的流配对成单个流所以我们可以将它映射到一个会改变的结果类中就像UIState类一样但是以一种更通用的方式因为 Result.Success将公开一个字段数据。
sealed interface Resultout T {data class SuccessT(val data: T) : ResultTdata class Error(val exception: Throwable? null) : ResultNothingobject Loading : ResultNothing
}Flow上的 Kotlin 扩展可自动映射到Result中
fun T FlowT.asResult(): FlowResultT {return this.mapT, ResultT {Result.Success(it)}.onStart { emit(Result.Loading) }.catch { emit(Result.Error(it)) }
}将其映射到 UI 状态类中
return combine(followedAuthorIdsStream,authorStream,::Pair
).asResult()
.map { followedAuthorToAuthorResult -when (followedAuthorToAuthorResult) {is Result.Success - {val (followedAuthors, author) followedAuthorToAuthorResult.dataAuthorUiState.Success()}is Result.Loading - AuthorUiState.Loadingis Result.Error - AuthorUiState.Error}
}使用生命周期安全方法搜集状态
val uiState by viewModel.uiState.collectAsStateWithLifecycle()我正在使用 collectAsState() 并且没有注意到生命周期版本已经结束。
collectAsState()方法的提醒
Composable
public fun T StateFlowT.collectAsState(context: CoroutineContext
): StateT从此 StateFlow 收集值并通过 State 表示其最新值。StateFlow.value 用作初始值。每次有新值发布到 StateFlow 时返回的 State 都会更新从而导致每个 State.value 用法的重组。 Composable 中的方法引用
Composable
fun MyScreen(viewModel: ForYouViewModel) {ForYouScreen(onTopicCheckedChanged viewModel::updateTopicSelection,onAuthorCheckedChanged viewModel::updateAuthorSelection,saveFollowedTopics viewModel::saveFollowedInterests,onNewsResourcesCheckedChanged viewModel::updateNewsResourceSaved,)
}这使代码更具可读性特别是在这里您的眼睛需要关注 UI。 调用参考
Composable
fun MyScreen(viewModel: ForYouViewModel) {ForYouScreen(onTopicCheckedChanged { topicId, isChecked -viewModel.updateTopicSelection(topicId topicId, isChecked isChecked)},onAuthorCheckedChanged { authorId, isChecked -viewModel.updateAuthorSelection(authorId authorId, isChecked isChecked)},saveFollowedTopics { viewModel.saveFollowedInterests() },onNewsResourcesCheckedChanged { newsResourceId, isChecked -viewModel.updateNewsResourceSaved(newsResourceId newsResourceId,isChecked isChecked)},)
}多预览的注解
表示各种设备尺寸的多预览的注解。将此注解添加到Composable以呈现各种设备。
Preview(name phone, device spec:shapeNormal,width360,height640,unitdp,dpi480)
Preview(name landscape, device spec:shapeNormal,width640,height360,unitdp,dpi480)
Preview(name foldable, device spec:shapeNormal,width673,height841,unitdp,dpi480)
Preview(name tablet, device spec:shapeNormal,width1280,height800,unitdp,dpi480)
annotation class DevicePreviewsMultipreview注解表示不同设备尺寸的多个预览。可以将这个注解添加到Compose中的某个组件上以在不同设备上渲染多个预览界面。 Android允许您通过继承IssueRegistry来创建自定义lint规则示例如下我不会解释如何做因为我在我的项目中还没有成功地让它正常工作
class DesignSystemIssueRegistry : IssueRegistry()在最新的Android版本中他们创建了一个类来检查是否使用了他们自定义的组件而不是通用的组件。以下是他们编写的代码片段
class DesignSystemDetector : Detector(), Detector.UastScanner {...val METHOD_NAMES mapOf(MaterialTheme to NiaTheme,Button to NiaFilledButton,OutlinedButton to NiaOutlinedButton,...)
}我发现这对不知道项目中已经存在特定组件的新开发人员很有用。
Composable 扩展
它只适用于 LazyListScope、ColumnScope ……不适用于 Composable。
fun LazyListScope.MyItem() {item {// Your Composable}
}Composable
fun MyList() {LazyColumn {MyItem()}
}我发现这很有用例如在多个屏幕上共享可组合的粘性标头。
先前
Composable
fun MyStickyHeader() {// Composable
}Composable
fun MyList() {LazyColumn {stickyHeader {MyStickyHeader()}}
}之后
fun LazyListScope.MyStickyHeader() {stickyHeader {// Composable}
}Composable
fun MyList() {LazyColumn {MyStickyHeader()}
}参考链接 https://medium.com/romeo.prosecco/top-things-i-learned-on-now-in-android-dba991da1c0