该文章将是compose
基础系列中最后一篇,附带效应是这篇文章的重点,其余补充内容为如何在传统xml中集成compose
、compose
导航的使用
有了前面的了解,我们知道compose
中是由State
状态发生改变来使得可组函数发生重组,状态的改变应该是在可组合函数作用域中,但有时我们需要它发生在别的作用域,如定时弹出一个消息,这就需要附带效应出场了,compose
定义了一系列附带效应API,来运用在可组合函数作用域内外,发生状态改变的不同场景
LaunchedEffect
我们之前就已经使用过了,特别是在低级别动画时,LaunchedEffect
用于安全地调用挂起函数,本质就是启动一个协程,LaunchedEffect
的调用需要在可组合函数作用域内
LaunchedEffect
的执行分为以下三种,优先级由上到下:
LaunchedEffect
退出组合,将取消协程LaunchedEffect
使用的同一个key
,并且上次LaunchedEffect
没执行结束,则不执行LaunchedEffect
使用的不同的key
,并且上次LaunchedEffect
没执行结束,则取消上次执行,启动新的协程执行该次任务例子:
@Preview
@Composable
fun MyLaunchEffect() {
var state by remember { mutableStateOf(false) }
var count by remember { mutableStateOf(0) }
if (state) {
// key为Unit唯一值
LaunchedEffect(Unit) {
delay(3000)
count++
}
}
Box(modifier = Modifier
.size(50.dp)
.background(Color.Cyan)
.clickable { state = !state }
) {
Text("执行了${count}次")
}
}
先是点击两下的效果,由于state
为false
时,没有LaunchedEffect
的代码块,此时LaunchedEffect
会取消:
稍微改变下例子的代码,一旦状态发生改变,那么重复执行LaunchedEffect
:
@Preview
@Composable
fun MyLaunchEffect2() {
var state by remember { mutableStateOf(0) }
var count by remember { mutableStateOf(0) }
if (state > 0) {
// key为Unit唯一值
LaunchedEffect(Unit) {
delay(3000)
count++
}
}
Box(modifier = Modifier
.size(50.dp)
.background(Color.Cyan)
.clickable { state++ }
) {
Text("执行了${count}次")
}
}
点击三下的效果,LaunchedEffect
的key
唯一,并且重复执行,由于第一次没执行完,所以只会执行第一次的LaunchedEffect
:
改变例子代码,每次执行的key
不同:
@Preview
@Composable
fun MyLaunchEffect3() {
var state by remember { mutableStateOf(0) }
var count by remember { mutableStateOf(0) }
if (state > 0) {
// key为随机值
LaunchedEffect(UUID.randomUUID()) {
delay(3000)
// 置为0,防止不断重组导致一直执行LaunchedEffect
state = 0
count++
}
}
Box(modifier = Modifier
.size(50.dp)
.background(Color.Cyan)
.clickable { state++ }
) {
Text("执行了${count}次")
}
}
效果,取消了之前的LaunchedEffect
,隔了3秒后才发生count
状态改变:
rememberCoroutineScope
也是使用过的,它返回一个remember
的协程作用域,可以在可组合函数外使用,调用几次执行几次
例子:
@Preview
@Composable
fun MyRememberCoroutineScope() {
val scope = rememberCoroutineScope()
var count by remember { mutableStateOf(0) }
Box(modifier = Modifier
.size(50.dp)
.background(Color.Cyan)
.clickable {
scope.launch {
delay(3000)
count++;
}
}
) {
Text("执行了${count}次")
}
}
效果:
LaunchedEffect
一旦启动,同一个key
其内部的方法调用和引用都是final的,即无法更改,如果LaunchedEffect
内使用的外部引用可能发生改变,应该使用rememberUpdatedState
先来看一个例子,我在重组时生成一个随机数,并作为onTimeout()
的打印参数,将onTimeout()
传给MyRememberUpdatedState
,LaunchedEffect
内调用onTimeout()
打印这个随机数:
@Preview
@Composable
fun MyTimeout() {
var state by remember { mutableStateOf(false) }
Column {
// 1.生成随机数
val random = Random.nextInt()
Log.i("onTimeout", "return : $random")
MyRememberUpdatedState(state) {
// 4.打印随机数
Log.i("onTimeout", "onTimeout() return : $random")
}
Button(onClick = { state = !state }) {
Text("click")
}
}
}
@Composable
fun MyRememberUpdatedState(enable: Boolean, onTimeout: () -> Unit) {
// 使用rememberUpdatedState
// val rememberUpdatedState by rememberUpdatedState(onTimeout)
val rememberUpdatedState = onTimeout
// 2.key唯一发生重组,不会重新执行
LaunchedEffect(true) {
delay(5000)
// 3.延迟5s,调用外部传入的onTimeout()
rememberUpdatedState()
}
if (enable)
Text("hi")
else
Text("hello")
}
我点击多次,这次的效果直接看日志即可:
可以看到最后打印的结果,是第一次生成的随机数
我们尝试使用remember
,将onTimeout
作为State
状态并记住,并以onTimeout
作为key
使得每次onTimeout
发生改变,触发值的更新:
@Preview
@Composable
fun MyTimeout() {
var state by remember { mutableStateOf(false) }
Column {
// 1.生成随机数
val random = Random.nextInt()
Log.i("onTimeout", "return : $random")
MyRememberUpdatedState(state) {
// 4.打印随机数
Log.i("onTimeout", "onTimeout() return : $random")
}
Button(onClick = { state = !state }) {
Text("click")
}
}
}
@Composable
fun MyRememberUpdatedState(enable: Boolean, onTimeout: () -> Unit) {
// 使用rememberUpdatedState
// val rememberUpdatedState by rememberUpdatedState(onTimeout)
val rememberUpdatedState by remember(onTimeout) { mutableStateOf(onTimeout) }
// val rememberUpdatedState = onTimeout
// 2.key唯一发生重组,不会重新执行
LaunchedEffect(true) {
delay(5000)
// 3.延迟5s,调用外部传入的onTimeout()
rememberUpdatedState()
}
if (enable)
Text("hi")
else
Text("hello")
}
打印的结果,依然是第一次生成的随机数:
而rememberUpdatedState
可以始终保持最新的值,从而改变LaunchedEffect
运行时的引用的值
@Preview
@Composable
fun MyTimeout() {
var state by remember { mutableStateOf(false) }
Column {
// 1.生成随机数
val random = Random.nextInt()
Log.i("onTimeout", "return : $random")
MyRememberUpdatedState(state) {
// 4.打印随机数
Log.i("onTimeout", "onTimeout() return : $random")
}
Button(onClick = { state = !state }) {
Text("click")
}
}
}
@Composable
fun MyRememberUpdatedState(enable: Boolean, onTimeout: () -> Unit) {
// 使用rememberUpdatedState
val rememberUpdatedState by rememberUpdatedState(onTimeout)
// val rememberUpdatedState by remember{ mutableStateOf(onTimeout) }
// val rememberUpdatedState = onTimeout
// 2.key唯一发生重组,不会重新执行
LaunchedEffect(true) {
delay(5000)
// 3.延迟5s,调用外部传入的onTimeout()
rememberUpdatedState()
}
if (enable)
Text("hi")
else
Text("hello")
}
打印结果:
原理:首先我们知道remember
相当于创建了一个静态变量,如果不指定key
,只会初始化一次,重复调用remember
并不会更新引用,指定key
时,当key
发生变化,则会更新引用
LaunchedEffect
运行时会复制引用,新建变量指向传入的引用,所以此时无论外部变量的引用发生如何改变,并不会改变LaunchedEffect
内部变量的引用
rememberUpdatedState
在remember
的基础上做了更新值处理,每次调用到rememberUpdatedState
时,将值更新,也就是引用的值的更新,此时不管外部变量还是LaunchedEffect
内部变量的值引用都会发生变化,LaunchedEffect
调用的自然就是最新的方法了,下面是rememberUpdatedState
的源码:
@Composable
fun <T> rememberUpdatedState(newValue: T): State<T> = remember {
mutableStateOf(newValue)
}.apply { value = newValue }
DisposableEffect
可以在key
变化和移除时做一些善后工作,需实现onDispose
例子:
@Preview
@Composable
fun MyDisposableEffect() {
var state by remember { mutableStateOf(false) }
var text by remember { mutableStateOf("click") }
val scope = rememberCoroutineScope()
if (state) {
// 重组或移除时会调用onDispose
DisposableEffect(Unit) {
val job = scope.launch {
delay(3000)
text = "点了"
}
onDispose {
job.cancel()
text = "取消了"
}
}
}
Button(onClick = { state = !state }) {
Text(text)
}
}
效果,在3s内点击了两次,导致重组时移除DisposableEffect
而触发onDispose
:
SideEffect
会在可组合函数重组完成时调用,可以进行用户行为分析、日志记录等操作
例子:
@OptIn(ExperimentalAnimationApi::class)
@Preview
@Composable
fun MySideEffect() {
var enable by remember { mutableStateOf(false) }
Column {
AnimatedVisibility(
visible = enable,
enter = scaleIn(tween(2000)),
exit = scaleOut(tween(2000))
) {
MySideEffectText("hello world")
}
Button(onClick = { enable = !enable }) {
Text("click")
}
}
}
@Composable
fun MySideEffectText(text: String) {
SideEffect {
Log.i("SideEffect", "重组完成")
}
Text(text)
}
效果,如果组件重组完成了,连续点击导致动画重复执行,则不会触发重组:
produceState
会启动一个协程,并返回一个State
对象,用来将非 Compose
状态转换为 Compose
状态,即执行一些耗时操作,如网络请求,并将结果作为State
对象返回
例子:
@Preview
@Composable
fun MyProduceState() {
var visiable by remember { mutableStateOf(false) }
Column {
if (visiable)
Text(load().value)
Button(onClick = { visiable = !visiable }) {
Text("load")
}
}
}
@Composable
fun load(): State<String> {
return produceState(initialValue = "", producer = {
delay(2000);
value = "hi"
})
}
效果:
derivedStateOf
可以将一个或多个状态对象转变为其他的状态对象,一旦状态发生改变,只会在用到该derivedStateOf
状态的地方进行重组
例子,根据传入的list
,过滤高亮的元素,并展示到列表中:
val alpha = arrayOf("a", "b", "c", "d", "e", "f", "g", "h")
@Preview
@Composable
fun MyDerivedStateOf() {
val items = remember { mutableStateListOf<String>() }
Column {
Button(onClick = { items.add(alpha[Random.nextInt(alpha.size)]) }) {
Text("Add")
}
DerivedStateOf(items, highPriorityKeywords = listOf("a", "b"))
}
}
/**
* 拥有highPriorityKeywords的优先显示
*/
@Composable
fun DerivedStateOf(
lists: List<String>,
highPriorityKeywords: List<String> = listOf("Review", "Unblock", "Compose")
) {
// 需要高亮置顶的items
val highPriorityLists by remember(highPriorityKeywords) {
derivedStateOf { lists.filter { it in highPriorityKeywords } }
}
LazyColumn {
items(highPriorityLists) { value ->
Text(value, color = Color.Red)
}
items(lists) { value ->
Text(value)
}
}
}
效果:
snapshotFlow
可以将 Compose
的 State
转为Flow
,当在 snapshotFlow
块中读取的 State
对象之一发生变化时,如果新值与之前发出的值不相等,Flow
会向其收集器发出新值
@Preview
@Composable
fun MySnapshotFlow() {
val listState = rememberLazyListState()
val list = remember {
mutableListOf<Int>().apply {
repeat(1000) { index ->
this += index
}
}
}
LazyColumn(state = listState) {
items(list) {
Text("hi:${it}")
}
}
LaunchedEffect(Unit) {
snapshotFlow {
listState.firstVisibleItemIndex
}.collect { index ->
Log.i("collect", "${index}")
}
}
}
滚动查看日志:
Compose
中有一些效应(如 LaunchedEffect
、produceState
或 DisposableEffect
)会采用可变数量的参数和键来取消运行效应,并使用新的键启动一个新的效应。在实际开发中,灵活运用key
是否唯一来使得是否需要重启效应
官方推荐一次性替换整个布局,也可以替换部分布局,本身compose
就兼容传统xml
的方式,所以在传统的项目上集成compose
很容易
xml
中使用ComposeView
,表示一个加载compose
的控件:
<?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=".ComposeIntegrateActivity">
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="hello android"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.compose.ui.platform.ComposeView
android:id="@+id/composeView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/textView2" />
</androidx.constraintlayout.widget.ConstraintLayout>
Activity
中调用ComposeView
的setContent()
方法,并使用compose
:
class ComposeIntegrateActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_compose_integrate)
val composeView = findViewById<ComposeView>(R.id.composeView)
composeView.setContent {
MyComposeApplicationTheme {
MyText1()
}
}
}
@Composable
fun MyText1() {
Text("hi compose")
}
}
启动效果:
fragment
中要多一步绑定View树生命周期:
class BlankFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val disposeOnViewTreeLifecycleDestroyed =
ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed
val root = inflater.inflate(R.layout.fragment_blank, container, false)
root.findViewById<ComposeView>(R.id.fragment_composeView).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
MaterialTheme() {
// In Compose world
Text("Hello Compose!")
}
}
}
return root
}
}
compose
定义了全新的导航API,下面来开始使用它
def nav_version = "2.5.3"
implementation "androidx.navigation:navigation-compose:$nav_version"
NavHost
需要一个navController
用于控制导航到那个可组合项,startDestination
初始的可组合项,以及NavGraphBuilder
导航关系图
class NaviActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyComposeApplicationTheme {
MyNavi()
}
}
}
}
@Preview
@Composable
fun MyNavi() {
val navController = rememberNavController()
NavHost(navController = navController, startDestination = "home") {
composable("home") { Home() }
composable("message") { Message() }
composable("mine") { Mine() }
}
}
@Composable
fun Home() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Home")
}
}
@Composable
fun Message() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Message")
}
}
@Composable
fun Mine() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Mine")
}
}
效果:
接下来使用navController
来导航到不同的可组合项,下面是官方给出的示例的几种方式:
“friendslist”
并加到返回堆栈中navController.navigate("friendslist")
“friendslist”
之前,将所有内容从后堆栈中弹出到“home”
(不包含home)navController.navigate("friendslist") {
popUpTo("home")
}
“friendslist”
之前,从堆栈中弹出所有内容,包括“home”
navController.navigate("friendslist") {
popUpTo("home") { inclusive = true }
}
“search”
时,才能导航到“search”
目标地,避免在后堆栈的顶部有多个副本navController.navigate("search") {
launchSingleTop = true
}
例子:
我们给App添加上Scaffold
,并在底部导航栏进行navController
导航的控制
class NaviActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
MyComposeApplicationTheme {
Scene()
}
}
}
}
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun Scene() {
val navController = rememberNavController()
Surface(Modifier.background(MaterialTheme.colorScheme.surface)) {
Scaffold(
topBar = {
TopAppBar(
title = {
Text(
stringResource(id = R.string.app_name),
color = MaterialTheme.colorScheme.onPrimaryContainer
)
},
colors = TopAppBarDefaults.smallTopAppBarColors(
containerColor = MaterialTheme.colorScheme.primaryContainer
)
)
},
bottomBar = {
Row(
modifier = Modifier
.fillMaxWidth()
.background(MaterialTheme.colorScheme.primaryContainer)
.padding(10.dp),
horizontalArrangement = Arrangement.SpaceAround
) {
CompositionLocalProvider(LocalContentColor provides MaterialTheme.colorScheme.onPrimaryContainer) {
Icon(
Icons.Rounded.Home, contentDescription = null,
modifier = Modifier.clickable {
navController.navigate("home") {
launchSingleTop = true
popUpTo("home")
}
}
)
Icon(
Icons.Rounded.Email, contentDescription = null,
modifier = Modifier.clickable {
navController.navigate("message") {
launchSingleTop = true
popUpTo("message")
}
}
)
Icon(
Icons.Rounded.Face, contentDescription = null,
modifier = Modifier.clickable {
navController.navigate("mine") {
launchSingleTop = true
popUpTo("mine")
}
}
)
}
}
}
) { paddings ->
MyNavi(
modifier = Modifier.padding(paddings),
navController = navController,
startDestination = "home"
) {
composable("home") { Home() }
composable("message") { Message() }
composable("mine") { Mine() }
}
}
}
}
@Composable
fun MyNavi(
modifier: Modifier = Modifier,
navController: NavHostController,
startDestination: String,
builder: NavGraphBuilder.() -> Unit
) {
NavHost(
modifier = modifier,
navController = navController,
startDestination = startDestination
) {
builder()
}
}
@Composable
fun Home() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Home")
}
}
@Composable
fun Message() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Message")
}
}
@Composable
fun Mine() {
Box(
modifier = Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text("Mine")
}
}
效果:
Navigation Compose
还支持在可组合项目的地之间传递参数,方式为Restful
风格,这种风格的参数为必填:
MyNavi(
modifier = Modifier.padding(paddings),
navController = navController,
startDestination = "home/b1254"
) {
composable("home/{userId}") { Home() }
composable("message/{count}") { Message() }
composable("mine/{userId}") { Mine() }
}
...
// 导航时带入参数
navController.navigate("mine/a1587")
参数类型默认为字符串,也可以通过navArgument
指定参数的类型:
composable(
"home/{userId}",
arguments = listOf(navArgument("userId") { type = NavType.StringType })
) { Home() }
通过 lambda 中提供的NavBackStackEntry
中提取这些参数:
composable(
"home/{userId}",
arguments = listOf(navArgument("userId") { type = NavType.StringType })
) {navBackStackEntry ->
navBackStackEntry.arguments?.getString("userId")
Home()
}
可选参数可以使用:?argName={argName}
来添加:
composable(
"message?count={count}",
arguments = listOf(navArgument("count") {
type = NavType.IntType
defaultValue = 0
})
) { Message() }
深层链接照搬了官方文档:深层链接
如果你想要将特定的网址、操作或 MIME 类型与导航绑定,实现对外提供跳转应用的功能,那么使用深层链接可以很方便的实现这个功能
以url
为例,通过deepLinks
将url
进行绑定:
val uri = "https://www.example.com"
composable(
"profile?id={id}",
deepLinks = listOf(navDeepLink { uriPattern = "$uri/{id}" })
) { backStackEntry ->
Profile(navController, backStackEntry.arguments?.getString("id"))
}
在manifest
中注册配置:
<activity …>
<intent-filter>
...
<data android:scheme="https" android:host="www.example.com" />
</intent-filter>
</activity>
外部通过PendingIntent
进行跳转:
val id = "exampleId"
val context = LocalContext.current
val deepLinkIntent = Intent(
Intent.ACTION_VIEW,
"https://www.example.com/$id".toUri(),
context,
MyActivity::class.java
)
val deepLinkPendingIntent: PendingIntent? = TaskStackBuilder.create(context).run {
addNextIntentWithParentStack(deepLinkIntent)
getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)
}
随着业务的越来越复杂,导航图也可能分为模块化,可以在NavHost
作用域中使用navigation
进行封装:
NavHost(navController, startDestination = "home") {
...
// Navigating to the graph via its route ('login') automatically
// navigates to the graph's start destination - 'username'
// therefore encapsulating the graph's internal routing logic
navigation(startDestination = "username", route = "login") {
composable("username") { ... }
composable("password") { ... }
composable("registration") { ... }
}
...
}
使用扩展函数将更好的对模块进行封装:
fun NavGraphBuilder.loginGraph(navController: NavController) {
navigation(startDestination = "username", route = "login") {
composable("username") { ... }
composable("password") { ... }
composable("registration") { ... }
}
}
NavHost(navController, startDestination = "home") {
...
loginGraph(navController)
...
}
参考链接:Python字符串|istitle字符串可以通过切片的方式访问,但是不能对分片进行赋值,字符串是不可变的! 格式化字符串: 格式描述格式描述%%百分号%标记(多出来的%是转义作用) %c字符及其ASCII码%s字符串%d有符号整数(十进制)%u无符号整数(十进制)%o无符号整数(八进制) %x无符号整数(十六进制)%X无符号整数(十六进制大写字符)%e浮点数字(科学计数法)%E浮点数字(科学计数法,用E代替e)%f浮点数字(用小数点符号) %g浮点数字(根据值的不同自动选择%e或%f)%G浮点数字(类似于%g,根据值的不同自动选择%E或%f)%p指针(用十六进制打印值的内存地址)%n存储输出字符的数量放进参数列表的下一个变量中 一个简单的例子: >>>importmath >>>pi 3.141592653589793 >>>print'pi=%.5f'%pi pi=3.14159 如果要在格式化字符串里包括百分号,那么就必须使用 %%,这样python就不会将%误认为
一谈起数据分析,首先想到的就是数据,没有数据,谈何分析。 毕竟好的菜肴,没有好的原材料,是很难做的~ 所以本期小F就给大家分享一个获取数据的方法,只需三行代码就能搞定。「GoPUP」,大佬造的轮子,大概有100+的免费数据接口。GitHub:https://github.com/justinzm/gopup使用文档:http://doc.gopup.cn/#/README主要有指数数据、宏观经济数据、新经济数据、微博KOL数据、信息数据、生活数据、疫情数据等。#安装gopup pipinstallgopup--upgrade复制安装成功后,就能使用了。01微博指数获取指定关键词的微博指数。#微博指数 importgopupasgp df_index=gp.weibo_index(word="马保国",time_type="1month") print(df_index)复制time_type="1month";1hour,1day,1month,3month选其一。三行Python代码实现数据获取。 02百度指数获取指定关键词
Centreon+Nagios实战第七篇——安装NRPE把以上全部安装完成之后即完成了服务端的监控设置,要想利用服务端监控其他机器的性能,还需要在被禁控端安装NRPE和Nagios-plugin,当然如果要监控本机服务端性能,也需要在本机上安装NRPE。安装NRPE 首要条件 首先确保您已经安装了一下包 gccglibcglibc-commonopenssl-develperl下载安装cd/tmpwgethttps://github.com/NagiosEnterprises/nrpe/archive/nrpe-2-15.tar.gz tarzxvfnrpe-2-15.tar.gz复制拷贝nrpe.cfg文件到您的远程主机nrpe配置目录mkdir/usr/local/nagios/etc cpsample-config/nrpe.cfg/usr/local/nagios/etc复制当NRPE安装完成之后,您需要安装一个初始化系统xinetedyuminstallxinetd复制配置xineted 在这里,我们需要做一个配置老告诉xinted关于nrpe一些信息,转换到nrpesour
背景:线上的机器是使用的ECS,磁盘空间只有40G,而journal日志就占了5G左右,所以要限制其大小和保存时间。介绍:1、查看journal占用磁盘空间大小:journalctl--disk-usage2、指定journal占用磁盘空间大小:journalctl--vacuum-size=1G3、指定journal日志保存时间:journalctl--vacuum-time=1years4、查看具体服务的日志:journalctl-unginx.servicejournalctl-unginx.service-f 实时查看5、实时查看最新日志:journalctl-f6、查看尾部最新的n行日志:journalctl-n207、查看指定时间的日志:journalctl--since"20minago"journalctl--sinceyesterdayjournalctl--since09:00--until"1hourago"8、查看内核日志:journalctl-k9、查看系统启动日志:journalctl-b所以这里我们只需要指定下jo
鉴于今天的这两题题解都特别的短,所以把两题写在一起了。分别是461题简单难度的汉明距离和319题中等难度的灯泡开关。原题地址:https://leetcode-cn.com/problems/hamming-distance/和https://leetcode-cn.com/problems/bulb-switcher/题目描述:汉明距离: 两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。给出两个整数x和y,计算它们之间的汉明距离。注意:0≤x,y<231.灯泡开关:初始时有n个灯泡关闭。第1轮,你打开所有的灯泡。第2轮,每两个灯泡你关闭一次。第3轮,每三个灯泡切换一次开关(如果关闭则开启,如果开启则关闭)。第i轮,每i个灯泡切换一次开关。对于第n轮,你只切换最后一个灯泡的开关。找出n轮后有多少个亮着的灯泡。来源:力扣(LeetCode)著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。解题思路:汉明距离这题,其实很简单,两个不同数字的二进制位不同位置的数目,利用位运算的异或,可以得到位置不同的二进制位组成的数字N,利用Java的Intege
教你如何获取微信公众号的文章封面图片?需求:在微信打开一个公众号,获取公众号文章里面的原图片,右上角标注的图片。这还不简单,直接点到文章里面去,不就可以了?但是点进去之后发现文章里没有插图,没有办法另存为,怎么办?那就复制链接,在网页端打开链接,按f12键查看图片位置和路径,保存到本地啊,历史图文消息排版在网页中打不开,只有某篇具体文章才可以复制黏贴链接。这是我想要的右键单击感觉受到一万点的伤害,那么,今天要分享一个神技能。轻松get到微信公众号的文章封面图片哦。1:点进去这篇只有封面图片的文章,复制文章链接,在浏览器打开。2:右键查看源代码3:按CTRL+F快捷键 ,搜索“varmsg”4:高亮出来的部分代码如下所示:msg_title后面的就是图文消息的标题; msg_desc后面的值是图文消息的摘要内容;msg_cdn_url后面的值是封面图片url;msg_link后面的值是图文消息的链接地址;“msg_cdn_url=”后面的url就是我们要的封面图地址了5:复制粘贴“msg_cdn_url=”后面的url链接在浏览器打开,看到我们想要的这张图片;另存到本地就OK咯。结束,
Filter的生命周期包含几个方法 1、构造器方法 2、init初始化方法 第1,2步,在web工程启动的时候执行(Filter已经创建) 3、doFilter过滤方法 第3步,每次拦截到请求,就会执行 4、destroy销毁 第4步,停止web工程的时候,就会执行(停止web工程,也会销毁Filter过滤器) FilterConfig类见名知义,它是Filter过滤器的配置文件类。 Tomcat每次创建Filter的时候,也会同时创建一个FilterConfig类,这里包含了Filter配置文件的配置信息。 FilterConfig类的作用是获取filter过滤器的配置内容 1、获取Filter的名称filter-name的内容 2、获取在Filter中配置的init-param初始化参数 3、获取ServletContext对象上述链的前提是这些都控制的同一个资源 Filter的拦截路径 Filter过滤器它只关心请求的地址是否匹配,不关心请求的资源是否存在!!!
1.接口描述接口请求域名:iotvideoindustry.tencentcloudapi.com。 直播列表接口 默认接口请求频率限制:20次/秒。 APIExplorer提供了在线调用、签名验证、SDK代码生成和快速检索接口等能力。您可查看每次调用的请求内容和返回结果以及自动生成SDK调用示例。 2.输入参数以下请求参数列表仅列出了接口请求参数和部分公共参数,完整公共参数列表见公共请求参数。 参数名称 必选 类型 描述 Action 是 String 公共参数,本接口取值:DescribeLiveChannelList。 Version 是 String 公共参数,本接口取值:2020-12-01。 Region 是 String 公共参数,详见产品支持的地域列表。 Offset 是 Integer 偏移量 Limit 是 Integer 最大数 LiveChannelType 否 Integer 直播频道类型,1:固定直播;2:移动直播 RecordPlanId 否 String 直播录制计划ID,null:直播录制计划为空
0.项目介绍 1.项目后台部署 网易云音乐NodeJS版API文档 后台项目 网易云音乐API 网易云音乐Node.jsAPIservice 灵感来自 disoul/electron-cloud-music darknessomi/musicbox sqaiyan/netmusic-node greats3an/pyncm 环境要求 需要NodeJS8.12+环境 安装 $gitclonegit@github.com:Binaryify/NeteaseCloudMusicApi.git $npminstall 复制 或者 $gitclonehttps://github.com/Binaryify/NeteaseCloudMusicApi.git $npminstall 复制 运行 调用前务必阅读文档的调用前须知 $nodeapp.js 复制 服务器启动默认端口为3000,若不想使用3000端口,可使用以下命令:Mac/Linux $PORT=4000nodeapp.js 复制 windows下使用git-bash或者cmder等终端执行以下命令: $setPORT
upd:整体二分也顺便学了,比较简单不写。 概述 CDQ分治主要用于解决偏序问题。 通常是先按某一维排序,再递归处理分出来的左子问题对右子问题的答案,最后合并。 经典问题-逆序对 同时也是经典的二维偏序问题。 记属性组\((a,b)\),其中\(a\)表示位置,\(b\)表示值。 那么就是求\(a_i<a_j\)且\(b_i>b_j\)的个数。 然后就是对\(a\)排序,对\(b\)树状数组从前往后扫一遍统计即可。 时间复杂度\(\mathcalO(n\logn)\)。 三维偏序 陌上花开 有\(n\)个元素,第\(i\)个元素有\(a_i,b_i,c_i\)三个属性,设\(f(i)\)表示满足\(a_j\leqa_i\)且\(b_j\leqb_i\)且\(c_j\leqc_i\)且\(j\nei\)的\(j\)的数量。 对于\(d\in[0,n)\),求\(f(i)=d\)的数量。 \(1\leqn\leq10^5\),\(1\leqa_i,b_i,c_i\leqk\leq2\times10^5\)。 先按\(a\)维排序,再将左、右子区间按\(b\)维排序。 虽然现在\
//1.获取模块的完整路径。 stringpath1=System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName; //2.获取和设置当前目录(该进程从中启动的目录)的完全限定目录 stringpath2=System.Environment.CurrentDirectory; //3.获取应用程序的当前工作目录 stringpath3=System.IO.Directory.GetCurrentDirectory(); //4.获取程序的基目录 stringpath4=System.AppDomain.CurrentDomain.BaseDirectory; //5.获取和设置包括该应用程序的目录的名称 stringpath5=System.AppDomain.CurrentDomain.SetupInformation.ApplicationBase; //6.获取启动了应用程序的可执行文件的路径 stringpath6=System.Windows.Forms.Application.Startu
screen的主要功能就是在终端下线后,后端执行的命令可以继续。在Screen环境下,所有的会话都独立的运行,并拥有各自的编号、输入、输出和窗口缓存。用户可以通过快捷键在不同的窗口下切换,并可以自由的重定向各个窗口的输入和输出。 用法 screen[-AmRvx-ls-wipe][-d<作业名称>][-h<行数>][-r<作业名称>][-s][-S<作业名称>] 常用选项-s 指定建立新视窗时,所要执行的shell。 -x 加入已有的sreen作业或者恢复之前离线的screen作业。 -r<作业名称> 恢复离线的screen作业。 -ls或--list 显示目前所有的screen作业。 其他选项-A 将所有的视窗都调整为目前终端机的大小。-d<作业名称> 将指定的screen作业离线。-h<行数> 指定视窗的缓冲区行数。-m 即使目前已在作业中的screen作业,仍强制建立新的screen作业。-R 先试图恢复离线的作业。若找不到离线的作业,即建立新的screen作业。-S<作业名称> 指定
原文链接:https://blog.csdn.net/lmf496891416/article/details/111317377 1.格式: LOOPAT内表INTODATA(工作区)GROUPBY(字段=工作区-字段 size=GROUPSIZE"分组组数-- index=GROUPINDEX)"分组的组序号 ASCENDINGASSIGNINGFIELD-SYMBOL(<组>). LOOPATGROUP<组>ASSIGNINGFIELD-SYMBOL(<指针>). "对指针进行操作,和普通的loop循环相似 ENDLOOP. ENDLOOP.复制 2.简而言之:就是第一个loop循环是把内表进行分组,第二loop循环是把组里的数据循环读出来进行修改判断等操作。3.可以替代ATENDOF/ATNEWOF。4.具体实例-复制就能用 TYPES:BEGINOFty_employee, nameTYPEchar30, roleTYPEchar30, ageTYPEi, sexTYPEchar10, ENDOFty_employee, ty_e
下载地址:http://t.cn/Rf8GeUq 先安装sklearn库,anaconda在paddle环境中搜索scikit-learn,安装即可。 importnumpyasnp frommatplotlibimportcolors#画图 fromsklearnimportsvm fromsklearn.svmimportSVC fromsklearnimportmodel_selection importmatplotlib.pyplotasplt importmatplotlibasmpl defiris_type(s): it={b'Iris-setosa':0,b'Iris-versicolor':1,b'Iris-virginica':2} returnit[s] #加载数据 data_path='D:/home/aistudio/data/data5420/iris.data'#数据文件的路径 data=np.loadtxt(data_path,#数据文件路径 dtype=float,#数据类型 delimiter=',',#数据分隔符
真的很费脑筋,简易在写逻辑的时候找个清净点的地方 废话不多说 直接撸代码 <%@PageLanguage="C#"AutoEventWireup="true"CodeFile="jsxx_ckjgNew.aspx.cs"Inherits="wjtwh_Default"%> <!DOCTYPEhtml> <htmllang="zh-cn"> <headrunat="server"> <metacharset="UTF-8"> <metaname="viewport"content="width=device-width,initial-scale=1.0"> <title>上城区自查表模板(2020年06月份)</title> <linkrel="stylesheet"type="text/css"href="../css/css.css"/> <scriptsrc="../js/jquery-1.9.1.min.js"type="text
N个同学(N通常大于10),每人写一个0~100之间的有理数 (不包括0或100),交给裁判,裁判算出所有数字的平均值,然后乘以0.618(所谓黄金分割常数),得到G值。提交的数字最靠近G(取绝对值)的同学得到N分,离G最远的同学得到-2分,其他同学得0分。玩了几天以后,大家发现了一些很有意思的现象,比如黄金点在逐渐地往下移动。 现在请大家根据这个游戏规则,编一个可以多人一起玩的小游戏程序,要求如下: 1、本作业属于结对编程项目,必须由二人共同完成,并分别将本次作业过程发到博客,同时将本次作业源代码提交到codeing系统; 2、如果可能的话尽量以C/S或B/S方式实现,即利用服务器接收和处理所有玩家提交的数字,并将结果反馈给各玩家,玩家可以通过客户端提交的数字; 3、如果采用单机方式实现的话,需要为用户提供便利的输入界面; 4、该游戏每次至少可以运行10轮以上,
某php+mysql系统,mysql数据库中有个user表,其中有个code字段,类型是int(11),这个字段是保存一个随机数,用来找回密码的时候做验证,默认值是0。 找回密码时候的步骤是,首先填写自己邮箱,接收重置密码的邮件,点击链接,访问如下代码: if(!empty($_GET['email'])&&!empty($_GET['code'])) { if(!$db->count('user',"email='{$_GET['email']}'ANDcode='{$_GET['code']}'")) die('error'); $_SESSION['email']=$_GET['email']; ... } 在数据库中查找email=$
代码检查与走查 代码检查、走查以及可用性测试是三种主要的人工测试方法。人工测试技术在查找错误方面非常有效,应该在程序开始编码之后、基于计算机的测试开始之前使用这些方法。本章主要介绍的是代码检查与走查的相似之处,而它们的不同之处将在后续章节中介绍。 代码检查与走查都要求人们组成一个小组(一场"头脑风暴会")来阅读或直观检查特定的程序。 "头脑风暴会"的目标是找出错误来,但不必找出改正错误的方法。在代码走查中,一组开发人员(三到四人为最佳)对代码进行审核。其中 只有一人是代码的作者。因此,代码走查的主要工作是由其他人,而不是作者本人完成的,这和软件测试的第原则,也即"软件编写者往往不能有效地测试自己的软件"相符合。 代码检查与走查是对过去桌面检查过程(在提交测试前由程序员阅读自己程序的过程)的改进。因为在实施过程中,除了软件编写者本人,还有其他人参与进来。代码走查的另一个优点在于,一旦发现错误,通常就能在代码中对其进行精确定位,这就降低了调试(错误修正)的成本。在典型的程序中,这些方陆通常会有效地查找出30%-70%(这些方陆在测试过程结束时可以有效地查找出多达70%的已知错误)的逻辑设计