WorkManager的基本使用

目录

  • 一、WorkManager概述
    • 1. WorkManager的作用:
    • 2. WorkManager的各个角色
  • 二、依赖库的导入
  • 三、WorkManager几种基本使用
    • 1. 单一任务的执行
    • 2. 数据 互相传递
    • 3. 多个任务 顺序执行
    • 4. 重复执行后台任务
    • 5. 约束条件
    • 6. 证明 app被杀掉之后,还在后台执行
  • 四、WorkManager源码流程图

一、WorkManager概述

WorkManage: 排队和管理工作请求;将WorkRequest对象传递WorkManager的任务队列

(注意:如果未指定任何约束,WorkManager立即运行任务)

WorkStatus: 包含有关特点任务的信息;可以使用LiveData保存WorkStatus对象,监听任务状态;如LiveData

  你的任务不可能总是在前台,但是还要确保你的那么重要任务执行,就可以放置在后台执行,那么WorkManager就发挥其作用了。
  WorkManager是Android Jetpack提供执行后台任务管理的组件,它适用于需要保证系统即使应用程序退出也会运行的任务,WorkManager API可以轻松指定可延迟的异步任务以及何时运行它们,这些API允许您创建任务并将其交给WorkManager立即允许或在适当的时间运行。
  WorkManager根据设备API级别和应用程序状态等因素选择适当的方式来运行任务。如果WorkManager在应用程序运行时执行您的任务之一,WorkManager可以在您应用程序进程的新进程钟运行您的任务。如果您的应用程序未运行,WorkManager会选择一种合适的方式来安排后台任务–具体取决于设备API级别和包含的依赖项,WorkManager可能会使用JobScheduler,Firebase JobDispatcher或AlarmManager。

1. WorkManager的作用:

    1. 确保重要的后台任务,一定会被执行,后台任务(例如:非及时性的(请求服务器 及时性)上传、下载 ,同步数据等)
    1. 内部对电量进行了优化,不需要我们去处理电量优化了
    1. API 14 到最新版本,都可以使用WorkManager来管理你的后台任务
    1. 注意:WorkManager不能做保活操作
    1. 调度,管理,执行的后台任务的场景,通常是可延迟的后台任务

2. WorkManager的各个角色

  1. Worker:可以这样理解,指定需要执行的任务,可以成为Worker类的之类,在实现的方法钟,就可以执行任务逻辑了。
  2. WorkRequest:可以这样理解,执行一项单一的任务
    • 第一点:必须知道WorkRequest对象必须指定Work执行的任务
    • 第二点:需要知道WorkRequest都有一个自动生成的唯一ID,可以使用ID执行取消排队任务 或 获取任务状态等操作
    • 第三点:需要知道WorkRequest是一个抽象的类;系统默认实现子类OneTimeWorkRequest 或 PeriodicWorkRequest
    • 第四点:需要知道WorkRequest.Builder创建WorkRequest对象;相应的子类:OneTimeWorkRequest.Builder 或 PeriodicWorkRequest.Builder
    • 第五点:需要知道Constraints:指定对任务运行时间的限制(任务约束);使用Constraints.Builder创建Constraints对象,并传递给WorkRequest.Builder

二、依赖库的导入

在app目录下的build.gradle导入依赖库

// 导入WorkManager依赖
def work_version = "2.3.4"
implementation "androidx.work:work-runtime:$work_version"

三、WorkManager几种基本使用

布局文件 activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayoutxmlns: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"android:orientation="vertical"><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="测试后台任务1"android:onClick="testBackgroundWork1"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="测试后台任务2"android:onClick="testBackgroundWork2"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="测试后台任务3"android:onClick="testBackgroundWork3"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="测试后台任务4"android:onClick="testBackgroundWork4"/><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="测试后台任务5"android:onClick="testBackgroundWork5"/><LinearLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"><Buttonandroid:id="@+id/bt6"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="测试后台任务六"android:onClick="testBackgroundWork6"/><Buttonandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:text="SP归零"android:onClick="spReset"/></LinearLayout><Buttonandroid:layout_width="match_parent"android:layout_height="wrap_content"android:text="分析源码"android:onClick="codeStudy"android:layout_marginTop="20dp"/></LinearLayout>

1. 单一任务的执行

MainWorker1.kt

package com.example.myworkmanagerimport android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParameters// 最简单的执行任务
class MainWorker1(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters) {// 定义静态变量  相对于java static   const val相对于定义常量companion object { const val TAG = "abc" }// 后台任务 并且 异步的(原理:线程池执行Runnable)override fun doWork(): Result {Log.d(TAG, "MainWorker1 doWork: run started ...")try {Thread.sleep(3000)  // 睡眠} catch (e : InterruptedException) {e.printStackTrace()Result.failure()  // 本次任务失败} finally {Log.d(TAG, "MainWorker1 doWork: run end ...")}return Result.success()  // 本次任务完成}
}

MainActivity.kt

 /*** 最简单的 执行任务* 测试后台任务1*/fun testBackgroundWork1(view: View) {// OneTimeWorkRequest 单个 一次的任务val oneTimeWorkRequest = OneTimeWorkRequest.Builder(MainWorker1::class.java).build()WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)}

2. 数据 互相传递

MainWorker2.kt

package com.example.myworkmanagerimport android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.work.Data
import androidx.work.Worker
import androidx.work.WorkerParametersclass MainWorker2(context: Context, private val workerParameters: WorkerParameters) : Worker(context, workerParameters) {companion object {const val TAG = "abc"}// 后台任何 并且异步的(原理:线程池执行Runnable)@SuppressLint("RestrictedApi")override fun doWork(): Result {Log.d(TAG, "MainWorker2 dowork: 后台任务执行了")// 接收MainActivity传递过来的数据val dataString = workerParameters.inputData.getString("maiworker2")Log.d(TAG, "MainWorker2 dowork: 接收MainActivity传递过来的数据:$dataString")// 反馈数据给MainActivity// 把任务中的数据回传到MainActivity中val outputData = Data.Builder().putString("mainworker2", "mainworker2回传的数据").build()/*return Result.Failure()  // 本次执行 doWork任务时 失败return Result.Retry()    // 本次执行 doWork任务时 重试一次return Result.Success()  // 本次执行 doWork任务时 成功 执行任务完毕*/return Result.Success(outputData);}
}

MainActivity.kt

    /*** 数据 互相传递* 测试后台任务2* 单个任务状态:ENQUEUED、RUNNING、SUCCEEDED*/fun testBackgroundWork2(view: View) {// 单一、一次的任务val oneTimeWorkRequest : OneTimeWorkRequest// 数据val sendData = Data.Builder().putString("mainworker2", "传给mainworker2的数据").build()// 请求对象初始化oneTimeWorkRequest = OneTimeWorkRequest.Builder(MainWorker2::class.java).setInputData(sendData) // 数据的携带 发送 一般都是 携带到Request里面去 发送数据给WorkManager2.build()// 一般都是通过 状态机 接收 WorkManager2的回馈数据// 状态机(LiveData)才能接收 WorkManager 回馈的数据WorkManager.getInstance(this).getWorkInfoByIdLiveData(oneTimeWorkRequest.id).observe(this, Observer{ workInfo ->// 状态包含:ENQUEUED、RUNNING、SUCCEEDEDLog.d(MainWorker2.TAG, "状态:" + workInfo.state.name);// ENQUEUED, RUNNING 都取不到 回馈的数据,都是null// Log.d(MainWorker2.TAG, "取到了任务回传的数据:" + workInfo.outputData.getString("mainworker2"))if (workInfo.state.isFinished) {  // 判断成功 SUCCEEDED状态Log.d(MainWorker2.TAG, "取到了任务回传的数据:" + workInfo.outputData.getString("mainworker2"))}})WorkManager.getInstance(this).equals(oneTimeWorkRequest)}

3. 多个任务 顺序执行

MainWorker3.kt

package com.example.myworkmanagerimport android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParametersclass MainWorker3(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters){companion object { const val TAG = "abc" }@SuppressLint("RestrictedApi")override fun doWork(): Result {Log.d(TAG, "MainWorker3 doWork: 后台任务执行了")return Result.Success();  // 本次执行 doWork任务时 成功 执行任务完毕}
}

MainWorker4.kt

package com.example.myworkmanagerimport android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParametersclass MainWorker4(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters){companion object { const val TAG = "abc" }@SuppressLint("RestrictedApi")override fun doWork(): Result {Log.d(TAG, "MainWorker4 doWork: 后台任务执行了")return Result.Success();  // 本次执行 doWork任务时 成功 执行任务完毕}
}

MainWorker5.kt

package com.example.myworkmanagerimport android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParametersclass MainWorker5(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters){companion object { const val TAG = "abc" }@SuppressLint("RestrictedApi")override fun doWork(): Result {Log.d(TAG, "MainWorker5 doWork: 后台任务执行了")return Result.Success();  // 本次执行 doWork任务时 成功 执行任务完毕}
}

MainWorker6.kt

package com.example.myworkmanagerimport android.annotation.SuppressLint
import android.content.Context
import android.util.Log
import androidx.work.Worker
import androidx.work.WorkerParametersclass MainWorker6(context: Context, workerParameters: WorkerParameters) : Worker(context, workerParameters){companion object { const val TAG = "abc" }@SuppressLint("RestrictedApi")override fun doWork(): Result {Log.d(TAG, "MainWorker3 doWork: 后台任务执行了")return Result.Success();  // 本次执行 doWork任务时 成功 执行任务完毕}
}

MainActivity.kt

/*** 多个任务  顺序执行* 测试后台任务3*/fun testBackgroundWork3(view: View) {// 单一、一次的任务val oneTimeWorkRequest3 = OneTimeWorkRequest.Builder(MainWorker3::class.java).build()val oneTimeWorkRequest4 = OneTimeWorkRequest.Builder(MainWorker4::class.java).build()val oneTimeWorkRequest5 = OneTimeWorkRequest.Builder(MainWorker5::class.java).build()val oneTimeWorkRequest6 = OneTimeWorkRequest.Builder(MainWorker6::class.java).build()// 顺序执行 3 4 5 6WorkManager.getInstance(this).beginWith(oneTimeWorkRequest3).then(oneTimeWorkRequest4).then(oneTimeWorkRequest5).then(oneTimeWorkRequest6).enqueue()// 另外一种使用// 需求: 先执行3 4 最后执行6val oneTimeWorkRequests : MutableList<OneTimeWorkRequest> = ArrayList()   // 集合方式oneTimeWorkRequests.add(oneTimeWorkRequest3)oneTimeWorkRequests.add(oneTimeWorkRequest4)WorkManager.getInstance(this).beginWith(oneTimeWorkRequests).then(oneTimeWorkRequest6).enqueue()}

4. 重复执行后台任务

MainActivity.kt

    /*** 重复执行后台任务 非单个任务 ,多个任务* 单个任务状态:ENQUEUED、RUNNING、SUCCEEDED*/fun testBackgroundWork4(view: View) {// OneTimeWorkRequest 单个任务  不会轮询  执行一次就结束// 重复的任务  多次/循环/轮询 哪怕设置为10s轮询一次,那么最少轮询/循环一次 也要15分钟(google规定)// 不能小于15分钟,否则默认修改成15分钟val periodicWorkRequest = PeriodicWorkRequest.Builder(MainWorker3::class.java,10, TimeUnit.SECONDS).build()// 状态机 为什么一直都是ENQUEUED 和 RUNNING,因为 你是轮询的任务,SUCCEEDED// 如果是单个任务,就会看到SUCCEEDED结束任务// 监听状态WorkManager.getInstance(this).getWorkInfoByIdLiveData(periodicWorkRequest.id).observe(this, Observer {workInfo ->Log.d("abc", "状态:" + workInfo.state.name)  // ENQUEUED RUNNING  循环反复if(workInfo.state.isFinished) {Log.d("abc", "状态:isFinished = true 注意:后台任务已经完成了...")}})WorkManager.getInstance(this).equals(periodicWorkRequest)// 取消 任务的执行//WorkManager.getInstance(this).cancelWorkById(periodicWorkRequest.id);}

5. 约束条件

MainActivity.kt

/*** 约束条件,约束后台任务执行* 测试后台任务5*/fun testBackgroundWork5(view: View) {val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED)  // 必须是联网中.setRequiresCharging(true)    // 必须是充当中.setRequiresDeviceIdle(true)  // 必须是空闲时.build()/*** 除了上面设置的约束外,WorkManager还提供了以下的约束作为Work执行的条件:* setRequiredNetworkType:网络连接设置* setRequiresBatteryNotLow:是否为低电量时运行,默认false* setRequiresCharging:是否要插入设备(接入电源),默认false* setRequiresDeviceIdle:设备是否空闲,默认false* setRequiresStorageNotLow:设备可用存储是否不低于临界阈值*/// 请求对象val request = OneTimeWorkRequest.Builder(MainWorker3::class.java).setConstraints(constraints).build()// 加入队列WorkManager.getInstance(this).enqueue(request)}

6. 证明 app被杀掉之后,还在后台执行

MainActivity.kt

class MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)}
/*** 证明 app被杀掉之后,还在后台执行,通过写入文件的方式(SP)* 测试后台任务6*/fun testBackgroundWork6(view: View) {// 约束条件val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED)  // 约束条件 必须是网络连接.build()// 构建Requestval request = OneTimeWorkRequest.Builder(MainWorker7::class.java).setConstraints(constraints).build()// 加入队列WorkManager.getInstance(this).enqueue(request)}// SP归零fun spReset(view: View) {val sp = getSharedPreferences(MainWorker7.SP_NAME, Context.MODE_PRIVATE)sp.edit().putInt(MainWorker7.SP_KEY, 0).apply()updateToUI()}// 从SP里面获取值,显示到界面给用户看private fun updateToUI() {val sp = getSharedPreferences(MainWorker7.SP_NAME, Context.MODE_PRIVATE)val resultValue = sp.getInt(MainWorker7.SP_KEY, 0)bt6?.text = "测试后台任务6---$resultValue"}// 文件内容只要有变化,此函数就会执行override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) = updateToUI()}

MainActivity.kt 完整代码:

package com.example.myworkmanagerimport android.content.Context
import android.content.SharedPreferences
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.util.Log
import android.view.View
import androidx.lifecycle.Observer
import androidx.work.*
import kotlinx.android.synthetic.main.activity_main.*
import java.util.concurrent.TimeUnitclass MainActivity : AppCompatActivity(), SharedPreferences.OnSharedPreferenceChangeListener {override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)setContentView(R.layout.activity_main)}/*** 最简单的 执行任务* 测试后台任务1*/fun testBackgroundWork1(view: View) {// OneTimeWorkRequest 单个 一次的任务val oneTimeWorkRequest = OneTimeWorkRequest.Builder(MainWorker1::class.java).build()WorkManager.getInstance(this).enqueue(oneTimeWorkRequest)}/*** 数据 互相传递* 测试后台任务2* 单个任务状态:ENQUEUED、RUNNING、SUCCEEDED*/fun testBackgroundWork2(view: View) {// 单一、一次的任务val oneTimeWorkRequest : OneTimeWorkRequest// 数据val sendData = Data.Builder().putString("mainworker2", "传给mainworker2的数据").build()// 请求对象初始化oneTimeWorkRequest = OneTimeWorkRequest.Builder(MainWorker2::class.java).setInputData(sendData) // 数据的携带 发送 一般都是 携带到Request里面去 发送数据给WorkManager2.build()// 一般都是通过 状态机 接收 WorkManager2的回馈数据// 状态机(LiveData)才能接收 WorkManager 回馈的数据WorkManager.getInstance(this).getWorkInfoByIdLiveData(oneTimeWorkRequest.id).observe(this, Observer{ workInfo ->// 状态包含:ENQUEUED、RUNNING、SUCCEEDEDLog.d(MainWorker2.TAG, "状态:" + workInfo.state.name);// ENQUEUED, RUNNING 都取不到 回馈的数据,都是null// Log.d(MainWorker2.TAG, "取到了任务回传的数据:" + workInfo.outputData.getString("mainworker2"))if (workInfo.state.isFinished) {  // 判断成功 SUCCEEDED状态Log.d(MainWorker2.TAG, "取到了任务回传的数据:" + workInfo.outputData.getString("mainworker2"))}})WorkManager.getInstance(this).equals(oneTimeWorkRequest)}/*** 多个任务  顺序执行* 测试后台任务3*/fun testBackgroundWork3(view: View) {// 单一、一次的任务val oneTimeWorkRequest3 = OneTimeWorkRequest.Builder(MainWorker3::class.java).build()val oneTimeWorkRequest4 = OneTimeWorkRequest.Builder(MainWorker4::class.java).build()val oneTimeWorkRequest5 = OneTimeWorkRequest.Builder(MainWorker5::class.java).build()val oneTimeWorkRequest6 = OneTimeWorkRequest.Builder(MainWorker6::class.java).build()// 顺序执行 3 4 5 6WorkManager.getInstance(this).beginWith(oneTimeWorkRequest3).then(oneTimeWorkRequest4).then(oneTimeWorkRequest5).then(oneTimeWorkRequest6).enqueue()// 另外一种使用// 需求: 先执行3 4 最后执行6val oneTimeWorkRequests : MutableList<OneTimeWorkRequest> = ArrayList()   // 集合方式oneTimeWorkRequests.add(oneTimeWorkRequest3)oneTimeWorkRequests.add(oneTimeWorkRequest4)WorkManager.getInstance(this).beginWith(oneTimeWorkRequests).then(oneTimeWorkRequest6).enqueue()}/*** 重复执行后台任务 非单个任务 ,多个任务* 单个任务状态:ENQUEUED、RUNNING、SUCCEEDED*/fun testBackgroundWork4(view: View) {// OneTimeWorkRequest 单个任务  不会轮询  执行一次就结束// 重复的任务  多次/循环/轮询 哪怕设置为10s轮询一次,那么最少轮询/循环一次 也要15分钟(google规定)// 不能小于15分钟,否则默认修改成15分钟val periodicWorkRequest = PeriodicWorkRequest.Builder(MainWorker3::class.java,10, TimeUnit.SECONDS).build()// 状态机 为什么一直都是ENQUEUED 和 RUNNING,因为 你是轮询的任务,SUCCEEDED// 如果是单个任务,就会看到SUCCEEDED结束任务// 监听状态WorkManager.getInstance(this).getWorkInfoByIdLiveData(periodicWorkRequest.id).observe(this, Observer {workInfo ->Log.d("abc", "状态:" + workInfo.state.name)  // ENQUEUED RUNNING  循环反复if(workInfo.state.isFinished) {Log.d("abc", "状态:isFinished = true 注意:后台任务已经完成了...")}})WorkManager.getInstance(this).equals(periodicWorkRequest)// 取消 任务的执行//WorkManager.getInstance(this).cancelWorkById(periodicWorkRequest.id);}/*** 约束条件,约束后台任务执行* 测试后台任务5*/fun testBackgroundWork5(view: View) {val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED)  // 必须是联网中.setRequiresCharging(true)    // 必须是充当中.setRequiresDeviceIdle(true)  // 必须是空闲时.build()/*** 除了上面设置的约束外,WorkManager还提供了以下的约束作为Work执行的条件:* setRequiredNetworkType:网络连接设置* setRequiresBatteryNotLow:是否为低电量时运行,默认false* setRequiresCharging:是否要插入设备(接入电源),默认false* setRequiresDeviceIdle:设备是否空闲,默认false* setRequiresStorageNotLow:设备可用存储是否不低于临界阈值*/// 请求对象val request = OneTimeWorkRequest.Builder(MainWorker3::class.java).setConstraints(constraints).build()// 加入队列WorkManager.getInstance(this).enqueue(request)}/*** 证明 app被杀掉之后,还在后台执行,通过写入文件的方式(SP)* 测试后台任务6*/fun testBackgroundWork6(view: View) {// 约束条件val constraints = Constraints.Builder().setRequiredNetworkType(NetworkType.CONNECTED)  // 约束条件 必须是网络连接.build()// 构建Requestval request = OneTimeWorkRequest.Builder(MainWorker7::class.java).setConstraints(constraints).build()// 加入队列WorkManager.getInstance(this).enqueue(request)}// SP归零fun spReset(view: View) {val sp = getSharedPreferences(MainWorker7.SP_NAME, Context.MODE_PRIVATE)sp.edit().putInt(MainWorker7.SP_KEY, 0).apply()updateToUI()}// 从SP里面获取值,显示到界面给用户看private fun updateToUI() {val sp = getSharedPreferences(MainWorker7.SP_NAME, Context.MODE_PRIVATE)val resultValue = sp.getInt(MainWorker7.SP_KEY, 0)bt6?.text = "测试后台任务6---$resultValue"}// 文件内容只要有变化,此函数就会执行override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) = updateToUI()// TODO ------------------------下面是源码分析环节/*** TODO 分析源码*/fun codeStudy(view: View) {// 没有约束条件// 请求对象val request = OneTimeWorkRequest.Builder(MainWorker3::class.java).build()// 第一次初始化是在 ContentProvider/*** APK 清单文件里面(第一次初始化)执行* 成果 WorkManagerImpl构建出来了* 1. 初始化 数据库 ROOM 来保存你的任务(持久性保存的)手机重启 APP被杀掉  没关系 一定执行* 2. 初始化 埋下伏笔 new GreedyScheduler(context, taskExcutor, this)* 3. 初始化 配置信息 configuration (执行信息  线程池任务)*/WorkManager.getInstance(this) // 这里已经是第二次初始化了.enqueue(request)  // 执行流程源码分析}}

四、WorkManager源码流程图

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/118078.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Linux - Docker 安装使用 常用命令 教程

Docker 官方文档地址: Get Started | Docker 中文参考手册: https://docker_practice.gitee.io/zh-cn/ 1.什么是 Docker 1.1 官方定义 最新官网首页 # 1.官方介绍 - We have a complete container solution for you - no matter who you are and where you are on your contain…

[SWPUCTF 2022]——Web方向 详细Writeup

SWPUCTF 2022 ez_ez_php 打开环境得到源码 <?php error_reporting(0); if (isset($_GET[file])) {if ( substr($_GET["file"], 0, 3) "php" ) {echo "Nice!!!";include($_GET["file"]);} else {echo "Hacker!!";} }e…

Python爬虫抓取经过JS加密的API数据的实现步骤

随着互联网的快速发展&#xff0c;越来越多的网站和应用程序提供了API接口&#xff0c;方便开发者获取数据。然而&#xff0c;为了保护数据的安全性和防止漏洞&#xff0c;一些API接口采用了JS加密技术这种加密技术使得数据在传输过程中更加安全&#xff0c;但也给爬虫开发带来…

QT基础教程之九Qt文件系统

QT基础教程之九Qt文件系统 文件操作是应用程序必不可少的部分。Qt 作为一个通用开发库&#xff0c;提供了跨平台的文件操作能力。Qt 通过QIODevice提供了对 I/O 设备的抽象&#xff0c;这些设备具有读写字节块的能力。下面是 I/O 设备的类图&#xff08;Qt5&#xff09;&#…

ROS 2官方文档(基于humble版本)学习笔记(一)

ROS 2官方文档&#xff08;基于humble版本&#xff09;学习笔记&#xff08;一&#xff09; 一、安装ROS 2二、按教程学习1.CLI 工具配置环境使用turtlesim&#xff0c;ros2和rqt安装 turtlesim启动 turtlesim使用 turtlesim安装 rqt使用 rqt重映射关闭turtlesim 由于市面上专门…

浅析Linux虚拟网络技术

文章目录 概述Tap/tun设备tun/tap的工作机制 Bridge网桥Bridge的工作机制Bridge IP 相关参考 概述 在传统的网络环境中&#xff0c;一台物理主机包含一张或多张网卡&#xff0c;要实现与其它物理主机之间的通信&#xff0c;需要将自身的网卡通过路由器或者交换机连接到外部的物…

Python零基础超详细教程:字典(Dictionary)相关介绍使用

前言 嗨喽~大家好呀&#xff0c;这里是魔王呐 ❤ ~! Python字典是另一种可变容器模型&#xff0c; 且可存储任意类型对象&#xff0c;如字符串、数字、元组等其他容器模型。 python更多源码/资料/解答/教程等 点击此处跳转文末名片免费获取 一、创建字典 字典由键和对应值…

ThreeJS 模型中内嵌文字

之前有过模型中内嵌html网页&#xff0c;地址☞threeJS 模型中加载html页面_threejs 加载dom元素_小菜花29的博客-CSDN博客 这次是纯粹的在模型中嵌入文本信息&#xff0c;进行简单的文字展示 展示效果图 1. 使用FontLoader文字加载器 引入文本json文件&#xff0c;代码如下…

事务的总结

数据库事务 数据库事务是一个被视为单一的工作单元的操作序列。这些操作应该要么完整地执行&#xff0c;要么完全不执行。事务管理是一个重要组成部分&#xff0c;RDBMS 面向企业应用程序&#xff0c;以确保数据完整性和一致性。事务的概念可以描述为具有以下四个关键属性描述…

04-过滤器和拦截器有什么区别?【Java面试题总结】

过滤器和拦截器有什么区别&#xff1f; 运行顺序不同&#xff1a;过滤器是在 Servlet 容器接收到请求之后&#xff0c;但在 Servlet被调用之前运行的&#xff1b;而拦截器则是在Servlet 被调用之后&#xff0c;但在响应被发送到客户端之前运行的。 过滤器Filter 依赖于 Servle…

VB.NET 如何将某个Excel的工作表中复制到另一个的Excel中的工作表中https://bbs.csdn.net/topics/392861034

参考http://share.freesion.com/306372/可以实现直接拷贝指定表 Private Sub Excel复制工作簿()Dim myExcelApp As New Microsoft.Office.Interop.Excel.ApplicationmyExcelApp.Workbooks.Open(System.Environment.CurrentDirectory "\\测试用例.xlsx", Type.Missin…

PostgreSQL本地化

本地化的概念 本地化的目的是支持不同国家、地区的语言特性、规则。比如拥有本地化支持后&#xff0c;可以使用支持汉语、法语、日语等等的字符集。除了字符集以外&#xff0c;还有字符排序规则和其他语言相关规则的支持&#xff0c;例如我们知道(‘a’,‘b’)该如何排序&…

React-native环境配置与项目搭建

基础环境搭建 安装 node.js &#xff08;版本>12 ,推荐安装LTS稳定版本&#xff09; 安装 Yarn &#xff08;npm install -g yarn&#xff09; 安装 react native 脚手架 (npm install -g react-native-cli) windows 只能搭建Android 开发环境 Mac 下既能搭建Android 环境&…

使用PAM保障开发运营安全

硬编码凭据和 DevOps 系统中缺乏凭据安全性是组织的巨大漏洞。以明文形式访问凭据的恶意内部人员可以在 IT 中建立和扩展其立足点 基础设施&#xff0c;构成巨大的数据被盗风险。 什么是PAM 特权访问管理 &#xff08;PAM&#xff09; 是指一组 IT 安全管理原则&#xff0c;可…

合宙Air724UG LuatOS-Air LVGL API控件--日历 (Calendar)

日历 (Calendar) LVGL 提供了一个用来选择和显示当前日期的日历控件。 示例代码 – 高亮显示的日期 highlightDate lvgl.calendar_date_t() – 日历点击的回调函数 – 将点击日期设置高亮 function event_handler(obj, event) if event lvgl.EVENT_VALUE_CHANGED then da…

ITMS介绍

ITMS&#xff08;Integrated Terminal Management System&#xff09;&#xff0c;终端综合管理系统。 主要用于家庭网关的设备注册&#xff0c;初始化自动配置&#xff0c;软件版本升级&#xff0c;远程故障诊断修复和设备监控等。它通过北向连接服开系统用于接收业务工单&am…

汽车自适应巡航系统控制策略研究

目 录 第一章 绪论 .............................................................................................................................. 1 1.1 研究背景及意义 ..........................................................................................…

已解决下载安装Python官网安装包下载速度慢问题

本文摘要&#xff1a;本文已解决下载安装Python官网安装包下载速度慢的问题。 &#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究…

无涯教程-机器学习 - 矩阵图函数

相关性是有关两个变量之间变化的指示&#xff0c;在前面的章节中&#xff0c;无涯教程讨论了Pearson的相关系数以及相关的重要性&#xff0c;可以绘制相关矩阵以显示哪个变量相对于另一个变量具有较高或较低的相关性。 在以下示例中&#xff0c;Python脚本将为Pima印度糖尿病数…

LNMP架构:搭建Discuz论坛

文章目录 1. 编译安装Nginx1.1 前置准备1.2 编译安装1.3 添加nginx系统服务 2.编译安装MySql2.1 前置准备2.2 编译安装2.3 修改mysql 配置文件2.4 设置路径环境变量2.5 初始化数据库2.6 添加musql系统服务2.7 修改MySql登录密码 3. 编译安装PHP3.1 前置准备3.2 编译安装3.3 复制…