【软件干货】Android应用进程如何保活?
1.Android 应用进程保活方法介绍
在Android应用程序中,为了保证应用的正常运行和稳定性,有时需要对应用进程进行保活。以下是一些实现进程保活的方法:
1、使用前台服务(Foreground Service):将服务调用startForeground()方法,并传入一个通知对象,将该服务置于前台运行状态。这样可以使得该服务的优先级更高,从而减少被系统杀死的概率。
2、使用JobScheduler:使用setPeriodic()方法可以让应用程序周期性地执行任务,从而避免长时间占用CPU资源,setPersisted(true)方法则表示当设备重启后,该任务仍然需要继续执行。
3、使用AlarmManager:使用这个API可以让应用程序在指定的时间间隔内执行任务。例如,可以设置一个闹钟,每隔一段时间唤醒应用程序并执行一些操作。
4、使用守护进程:启动一个后台守护进程,监控应用程序的状态并在应用程序被杀死时重新启动它,使用守护进程需要申请额外的权限。
5、使用双进程保活:启动两个相互绑定的进程,在其中一个进程被杀死时,另一个进程可以重新启动它。
6、使用WorkManger: 这是目前比较新的保活机制,用于取代JobScheduler。
需要注意的是,为了避免滥用和浪费系统资源,Android系统不断升级后,已经严格限制应用程序使用过多的后台资源和保活机制。
2.JobScheduler 用法简介
JobScheduler 是系统服务,由系统负责调度第三方应用注册的JobScheduler ,定时完成指定任务。
在应用中创建一个 JobService 服务,JobService 需要 API Level 21以上才可以使用,该服务注册时必须声明 android.permission.BIND_JOB_SERVICE 权限:
<!-- JobScheduler 拉活 --><serviceandroid:name=".jobscheduler.KeepAliveJobService"android:enabled="true"android:exported="true"android:permission="android.permission.BIND_JOB_SERVICE"></service>
通常使用JobScheduler需要以下几个步骤:
1、获取 JobScheduler 对象:通过Binder机制获取该JobScheduler系统服务;
// 创建 JobSchedulerJobScheduler jobScheduler =(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);
2、指定 JobScheduler 任务信息 JobInfo:绑定任务 ID,指定任务的运行组件,也就是之前创建并注册的 JobService, 最后要设置该任务在重启后也要执行;
// 第一个参数指定任务 ID// 第二个参数指定任务在哪个组件中执行// setPersisted 方法需要 android.permission.RECEIVE_BOOT_COMPLETED 权限// setPersisted 方法作用是设备重启后 , 依然执行 JobScheduler 定时任务JobInfo.Builder jobInfoBuilder = new JobInfo.Builder(10,new ComponentName(context.getPackageName(), KeepAliveJobService.class.getName())).setPersisted(true);
3、设置时间信息:7.0 以下的系统可以设置间隔, 7.0 以上的版本需要设置延迟执行,否则无法启动;
// 7.0 以下的版本, 可以每隔 5000 毫秒执行一次任务if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N){jobInfoBuilder.setPeriodic(5_000);}else{// 7.0 以上的版本 , 设置延迟 5 秒执行// 该时间不能小于 JobInfo.getMinLatencyMillis 方法获取的最小值jobInfoBuilder.setMinimumLatency(5_000);}
4、开启定时任务;
// 开启定时任务jobScheduler.schedule(jobInfoBuilder.build());
5、7.0 以上的特殊处理,由于在7.0 以上的系统中设置了延迟执行,需要在JobService 的 onStartJob 方法中再次开启一次 JobScheduler 任务执行,也就是重复上述1 ~ 4执行, 这样就实现了周期性执行的目的;
public class KeepAliveJobService extends JobService {@Overridepublic boolean onStartJob(JobParameters params) {Log.i("KeepAliveJobService", "JobService onStartJob 开启");if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){// 如果当前设备大于 7.0 , 延迟 5 秒 , 再次执行一次startJob(this);}return false;}}
3.WorkManager用法简介
WorkManager是适合用于持久性工作的推荐解决方案,它可处理三种类型的持久性工作:
1、立即执行:必须立即开始且很快就完成的任务,可以加急。
2、长时间运行:运行时间可能较长(有可能超过 10 分钟)的任务。
3、可延期执行:延期开始并且可以定期运行的预定任务。
通常使用WorkManager需要以下几个步骤:
1、将依赖项添加到应用的build.gradle文件中;
2、定义工作:工作使用 Worker 类定义,doWork() 方法在 WorkManager 提供的后台线程上异步运行。如需为 WorkManager 创建一些要运行的工作,则需扩展 Worker 类并替换 doWork() 方法;
public class XxxWorker extends Worker {publicXxxWorker(@NonNull Context context,@NonNull WorkerParameters params) {super(context, params);}@Overridepublic Result doWork() {// Do the work herexxxxx();// Indicate whether the work finished successfully with the Resultreturn Result.success();}}
3、创建 WorkRequest:定义工作后,必须使用WorkManager 服务进行调度该工作才能运行;
WorkRequest xxxWorkRequest =new OneTimeWorkRequest.Builder(XxxWorker.class).build();
4.将 WorkRequest 提交给系统:需要使用enqueue()方法将WorkRequest提交到WorkManager;
WorkManager.getInstance(myContext).enqueue(uploadWorkRequest);
在定义工作时要考虑要考虑下面常见的需求:
1、调度一次性工作还是重复性工作;
2、工作约束条件是怎样的,例如要求连接到 Wi-Fi 网络或正在充电;
3、确保至少延迟一定时间再执行工作;
4、设置重试和退避策略;
5、输入数据如何传递给工作等等。
4.双进程保活
双进程保活的方式就是在运行了一个主进程之外,还运行了一个 “本地前台进程”,并绑定“远程前台进程”, “远程前台进程”与“本地前台进程”实现了相同的功能,代码基本一致,这两个进程都是前台进程,都进行了提权,并且互相绑定,当监听到绑定的另外一个进程突然断开连接,则本进程再次开启前台进程提权,并且重新绑定对方进程,以达到拉活对方进程的目的。
双进程保活的实现步骤如下:
1、定义 AIDL 接口 IMyAidlInterface,每个服务中都需要定义继承 IMyAidlInterface.Stub 的 Binder 类,作为进程间通信的桥梁( 这是个默认的 AIDL 接口 ),监听进程的连接断开;
// Declare any non-default types here with import statementsinterface IMyAidlInterface {/*** Demonstrates some basic types that you can use as parameters* and return values in AIDL.*/void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString);}
2、实现一个判定服务运行工具:
import android.app.Activity;import android.app.ActivityManager;import android.content.Context;import android.text.TextUtils;import org.w3c.dom.Text;import java.util.List;public class ServiceUtils {/*** 判定 Service 是否在运行* @param context* @return*/public static boolean isServiceRunning(Context context, String serviceName){if(TextUtils.isEmpty(serviceName)) return false;ActivityManager activityManager =(ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);// 最多获取 200 个正在运行的 ServiceList<ActivityManager.RunningServiceInfo> infos =activityManager.getRunningServices(200);// 遍历当前运行的 Service 信息, 如果找到相同名称的服务 , 说明某进程正在运行for (ActivityManager.RunningServiceInfo info: infos){if (TextUtils.equals(info.service.getClassName(), serviceName)){return true;}}return false;}}
3、定义一个用于本地与远程连接的类:
class Connection implements ServiceConnection {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 服务绑定成功时回调}@Overridepublic void onServiceDisconnected(ComponentName name) {// 再次启动前台进程startService();// 绑定另外一个远程进程bindService();}}
4、定义一个本地前台服务类:
import android.app.Notification;import android.app.NotificationChannel;import android.app.NotificationManager;import android.app.Service;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.graphics.Color;import android.os.Build;import android.os.IBinder;import android.os.RemoteException;import androidx.core.app.NotificationCompat;import static androidx.core.app.NotificationCompat.PRIORITY_MIN;/*** 本地前台服务*/public class LocalForegroundService extends Service {/*** 远程调用 Binder 对象*/private MyBinder myBinder;/*** 连接对象*/private Connection connection;/*** AIDL 远程调用接口* 其它进程调与该 RemoteForegroundService 服务进程通信时 , 可以通过 onBind 方法获取该 myBinder 成员* 通过调用该成员的 basicTypes 方法 , 可以与该进程进行数据传递*/class MyBinder extends IMyAidlInterface.Stub {@Overridepublic void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString) throws RemoteException {// 通信内容}}@Overridepublic IBinder onBind(Intent intent) {return myBinder;}@Overridepublic void onCreate() {super.onCreate();// 创建 Binder 对象myBinder = new MyBinder();// 启动前台进程startService();}private void startService(){if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){// startForeground();// 创建通知通道NotificationChannel channel = new NotificationChannel("service","service", NotificationManager.IMPORTANCE_NONE);channel.setLightColor(Color.BLUE);channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);// 正式创建service.createNotificationChannel(channel);NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "service");Notification notification = builder.setOngoing(true).setSmallIcon(R.mipmap.ic_launcher).setPriority(PRIORITY_MIN).setCategory(Notification.CATEGORY_SERVICE).build();// 开启前台进程 , API 26 以上无法关闭通知栏startForeground(10, notification);} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){startForeground(10, new Notification());// API 18 ~ 25 以上的设备 , 启动相同 id 的前台服务 , 并关闭 , 可以关闭通知startService(new Intent(this, CancelNotificationService.class));} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2){// 将该服务转为前台服务// 需要设置 ID 和 通知// 设置 ID 为 0 , 就不显示已通知了 , 但是 oom_adj 值会变成后台进程 11// 设置 ID 为 1 , 会在通知栏显示该前台服务// 8.0 以上该用法报错startForeground(10, new Notification());}}/*** 绑定 另外一个 服务* LocalForegroundService 与 RemoteForegroundService 两个服务互相绑定*/private void bindService(){// 绑定另外一个 服务// LocalForegroundService 与 RemoteForegroundService 两个服务互相绑定// 创建连接对象connection = new Connection();// 创建本地前台进程组件意图Intent bindIntent = new Intent(this, RemoteForegroundService.class);// 绑定进程操作bindService(bindIntent, connection, BIND_AUTO_CREATE);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 绑定另外一个服务bindService();return super.onStartCommand(intent, flags, startId);}}
5、定义一个远程前台服务类:
import android.app.Notification;import android.app.NotificationChannel;import android.app.NotificationManager;import android.app.Service;import android.content.ComponentName;import android.content.Context;import android.content.Intent;import android.content.ServiceConnection;import android.graphics.Color;import android.os.Build;import android.os.IBinder;import android.os.RemoteException;import androidx.core.app.NotificationCompat;import static androidx.core.app.NotificationCompat.PRIORITY_MIN;/*** 远程前台服务*/public class RemoteForegroundService extends Service {/*** 远程调用 Binder 对象*/private MyBinder myBinder;/*** 连接对象*/private Connection connection;/*** AIDL 远程调用接口* 其它进程调与该 RemoteForegroundService 服务进程通信时 , 可以通过 onBind 方法获取该 myBinder 成员* 通过调用该成员的 basicTypes 方法 , 可以与该进程进行数据传递*/class MyBinder extends IMyAidlInterface.Stub {@Overridepublic void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,double aDouble, String aString) throws RemoteException {// 通信内容}}@Overridepublic IBinder onBind(Intent intent) {return myBinder;}@Overridepublic void onCreate() {super.onCreate();// 创建 Binder 对象myBinder = new MyBinder();// 启动前台进程startService();}private void startService(){if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){// startForeground();// 创建通知通道NotificationChannel channel = new NotificationChannel("service","service", NotificationManager.IMPORTANCE_NONE);channel.setLightColor(Color.BLUE);channel.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);NotificationManager service = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);// 正式创建service.createNotificationChannel(channel);NotificationCompat.Builder builder = new NotificationCompat.Builder(this, "service");Notification notification = builder.setOngoing(true).setSmallIcon(R.mipmap.ic_launcher).setPriority(PRIORITY_MIN).setCategory(Notification.CATEGORY_SERVICE).build();// 开启前台进程 , API 26 以上无法关闭通知栏startForeground(10, notification);} else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2){startForeground(10, new Notification());// API 18 ~ 25 以上的设备 , 启动相同 id 的前台服务 , 并关闭 , 可以关闭通知startService(new Intent(this, CancelNotificationService.class));} else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR2){// 将该服务转为前台服务// 需要设置 ID 和 通知// 设置 ID 为 0 , 就不显示已通知了 , 但是 oom_adj 值会变成后台进程 11// 设置 ID 为 1 , 会在通知栏显示该前台服务// 8.0 以上该用法报错startForeground(10, new Notification());}}/*** 绑定 另外一个 服务* LocalForegroundService 与 RemoteForegroundService 两个服务互相绑定*/private void bindService(){// 绑定 另外一个 服务// LocalForegroundService 与 RemoteForegroundService 两个服务互相绑定// 创建连接对象connection = new Connection();// 创建本地前台进程组件意图Intent bindIntent = new Intent(this, LocalForegroundService.class);// 绑定进程操作bindService(bindIntent, connection, BIND_AUTO_CREATE);}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 绑定另外一个服务bindService();return super.onStartCommand(intent, flags, startId);}}
6、启动两个服务:
import androidx.appcompat.app.AppCompatActivity;import android.content.Intent;import android.os.Bundle;public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);startService(new Intent(this, LocalForegroundService.class));startService(new Intent(this, RemoteForegroundService.class));}}
5.双进程保活+JobScheduler整合方案
这种方案是在 JobService的onStartJob 方法中判定“双进程保活”中的双进程是否挂了 ,如果这两个进程挂了,就重新将挂掉的进程重启。
这里给出一个双进程保活+JobScheduler整合方案中JobScheduler部分的示意代码,而双进程保活部分保持不变。
public class KeepAliveJobService extends JobService {@Overridepublic boolean onStartJob(JobParameters params) {Log.i("KeepAliveJobService", "JobService onStartJob 开启");if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){// 如果当前设备大于 7.0 , 延迟 5 秒 , 再次执行一次startJob(this);}// 判定本地前台进程是否正在运行boolean isLocalServiceRunning =ServiceUtils.isServiceRunning(this, LocalForegroundService.class.getName());if (!isLocalServiceRunning){startService(new Intent(this, LocalForegroundService.class));}// 判定远程前台进程是否正在运行boolean isRemoteServiceRunning =ServiceUtils.isServiceRunning(this, RemoteForegroundService.class.getName());if (!isRemoteServiceRunning){startService(new Intent(this, RemoteForegroundService.class));}return false;}@Overridepublic boolean onStopJob(JobParameters params) {Log.i("KeepAliveJobService", "JobService onStopJob 关闭");return false;}public static void startJob(Context context){// 创建 JobSchedulerJobScheduler jobScheduler =(JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE);// 第一个参数指定任务 ID// 第二个参数指定任务在哪个组件中执行// setPersisted 方法需要 android.permission.RECEIVE_BOOT_COMPLETED 权限// setPersisted 方法作用是设备重启后 , 依然执行 JobScheduler 定时任务JobInfo.Builder jobInfoBuilder = new JobInfo.Builder(10,new ComponentName(context.getPackageName(), KeepAliveJobService.class.getName())).setPersisted(true);// 7.0 以下的版本, 可以每隔 5000 毫秒执行一次任务if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N){jobInfoBuilder.setPeriodic(5_000);}else{// 7.0 以上的版本 , 设置延迟 5 秒执行// 该时间不能小于 JobInfo.getMinLatencyMillis 方法获取的最小值jobInfoBuilder.setMinimumLatency(5_000);}// 开启定时任务jobScheduler.schedule(jobInfoBuilder.build());}}
参考文献
1、【Android 进程保活】应用进程拉活 ( 双进程守护 + JobScheduler 保活):https://hanshuliang.blog.csdn.net/article/details/115607584
2、【Android 进程保活】应用进程拉活 ( 双进程守护保活 ):https://hanshuliang.blog.csdn.net/article/details/115604667
3、【Android 进程保活】应用进程拉活 ( JobScheduler 拉活):https://hanshuliang.blog.csdn.net/article/details/115584240
4、Android实现进程保活的思路:https://blog.csdn.net/gs12software/article/details/130502312
5、WorkManager 使用入门:https://developer.android.google.cn/develop/background-work/background-tasks/persistent/getting-started
相关文章:
【软件干货】Android应用进程如何保活?
1.Android 应用进程保活方法介绍 在Android应用程序中,为了保证应用的正常运行和稳定性,有时需要对应用进程进行保活。以下是一些实现进程保活的方法: 1、使用前台服务(Foreground Service):将服务调用startForeground()方法&…...
neo4j部署保姆级教程
由于公司是基于大数据架构的,让部署neo4j数据库,之前没有接触过,然后紧急学了一下,并且从网上找了一些教程,决定还是记录下来,后续有时间了会在出一篇使用教程 环境准备(root用户) …...
【STM32CubeMX开发】-2.2-TIM_输出一个PWM信号
目录 1 Tim定时器的时钟源 2 Tim定时器的配置 2.1 PWM配置 2.2 中断配置 3 生成代码 4 测试结果 结尾 1 Tim定时器的时钟源 TIM3的时钟来源自APB1 Timer clocks,时钟树上所有总线频率均设置为了STM32F0能达到的最高频率,此时APB1 Timer clocks …...
Ngx+Lua+Redis 快速存储POST数据
系统几万台设备有windows有安卓还有linux系统,每个设备三分钟就会向服务器post设备的硬件信息,数据格式json,后台管理界面只需要最新的数据,不需要历史数据,业务逻辑非常简单,PHP代码就几行,已经…...
go-delve的使用
go-delve的非交互使用方式: dlv要执行的命令文件:cmd.dlv goroutines exit 执行非交互命令: yes n | dlv --allow-non-terminal-interactivetrue attach $pid --init cmd.dlv --end--...
Python网络爬虫技术详解
Python网络爬虫技术详解 引言 网络爬虫(Web Crawler),又称网络蜘蛛(Web Spider)或网络机器人(Web Robot),是一种按照一定规则自动抓取互联网信息的程序或脚本。它们通过遍历网页链…...
Golang | Leetcode Golang题解之第474题一和零
题目: 题解: func findMaxForm(strs []string, m, n int) int {dp : make([][]int, m1)for i : range dp {dp[i] make([]int, n1)}for _, s : range strs {zeros : strings.Count(s, "0")ones : len(s) - zerosfor j : m; j > zeros; j--…...
算法刷题技巧
算法题:https://leetcode.cn/studyplan/top-100-liked/ 哈希表 使用哈希表,增删改查的时间复杂度均为O(1)。何时使用哈希表? 在某个区域内查找一个已知元素,可以使用哈希表作为这个区域根据一个特征对元素进行分类,特征…...
BMS、EMS PCS 简介
1 储能系统的构成 完整的电化学储能系统主要由电池组、电池管理系统(BMS)、能量管理系统(EMS)、储能变流器(PCS)以及其他电气设备构成。 在储能系统中,电池组将状态信息反馈给电池管理系统BMS&…...
spug3发布项目
一、启动spug项目 1.spug代码仓库地址: spug: 开源运维平台:面向中小型企业设计的无 Agent的自动化运维平台,整合了主机管理、主机批量执行、主机在线终端、文件在线上传下载、应用发布、任务计划、配置中心、监控、报警等一系列功能。 - Gitee.com 注…...
鸿蒙HarmonyOS开发:应用权限的基本概念及如何申请应用权限详细介绍
文章目录 一、访问控制二、应用权限1、应用权限管控2、权限使用的基本原则3、授权方式4、权限等级 三、申请应用权限1、选择申请权限的方式2、声明权限3、声明样例4、二次向用户申请授权5、具体实现示例6、效果展示 四、应用权限列表1、system_grant(系统授权&#…...
mac 桌面版docker no space left on device
报错信息 docker pull镜像时报: failed to register layer: Error processing tar file(exit status 1): write /home/admin/oceanbase_bak/bin/observer: no space left on device 解决 增加 docker 虚拟磁盘大小。 调整完点击重启即可。...
基于CIM的街镇基层治理统一指挥平台建设方案
1 项目概述 1.1 建设背景 社区作为人民生活的重要区域,往往需要对社区内人员、房屋、基本设施、日常业务进行规范管理,以保证其正常运行,但是传统的社区治理方式已不能满足新时代社会发展的要求,如人工采集录入信息、人员现场巡逻等,这些工作方式不仅工作量大,而且效率…...
PostgreSQL学习笔记三:数据类型和运算符
数据类型和运算符 PostgreSQL 支持多种数据类型和运算符,以下是一些常见的数据类型和运算符的概述: 数据类型 基本数据类型 整数类型: SMALLINT:2 字节,范围 -32,768 到 32,767。INTEGER:4 字节࿰…...
ROS理论与实践学习笔记——6 ROS机器人导航(仿真)
在 ROS 中,机器人导航(Navigation)是由多个功能包组合而成的系统,统称为导航功能包集(navigation stack)。它提供了一个全面的框架,使得移动机器人能够自主导航到指定目标点,同时避开…...
uniapp开发微信小程序,button的open-type=“share“ 分享给个人跳转到首页问题
当使用button标签带上open-type"share"属性,点击之后可分享当前页面给微信好友,但是分享之后朋友点开跳转到了首页问题。 需要使用 onShareAppMessage 函数 export default {onShareAppMessage(res) {if (res.from button) {// 来自页面内分…...
【jQuery】 jQuery基础及选择器介绍(基本选择器 层次选择器 属性选择器 过滤选择器)
文章目录 jQuery基础1. 优势2. 版本3. 基本语法4. 选择器基本选择器层次选择器属性选择器过滤选择器基本过滤选择器可见性过滤选择器 注意事项 jQuery基础 jQuery 是一个功能强大且易于使用的 JavaScript 库,它极大地简化了前端开发的工作。无论是 DOM 操作、事件处…...
网站在对抗机器人攻击的斗争中失败了
95% 的高级机器人攻击都未被发现,这一发现表明当前的检测和缓解策略存在缺陷。 这表明,虽然一些组织可能拥有基本的防御能力,但他们没有足够的能力应对更复杂的攻击。 例如利用人工智能和机器学习来模仿人类行为的攻击。 这些统计数据强调…...
Centos7 搭建logstash
下载并安装公共签名密钥: sudo rpm --import https://artifacts.elastic.co/GPG-KEY-elasticsearch 创建一个名为 /etc/yum.repos.d/logstash.repo 的文件,并添加以下内容: [logstash-7.x] nameElastic repository for 7.x packages baseu…...
面试题:Redis(五)
1. 面试题 面试问 记录对集合中的数据进行统计 在移动应用中,需要统计每天的新增用户数和第2天的留存用户数; 在电商网站的商品评论中,需要统计评论列表中的最新评论; 在签到打卡中,需要统计一个月内连续打卡的用户数&…...
深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
大话软工笔记—需求分析概述
需求分析,就是要对需求调研收集到的资料信息逐个地进行拆分、研究,从大量的不确定“需求”中确定出哪些需求最终要转换为确定的“功能需求”。 需求分析的作用非常重要,后续设计的依据主要来自于需求分析的成果,包括: 项目的目的…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
服务器硬防的应用场景都有哪些?
服务器硬防是指一种通过硬件设备层面的安全措施来防御服务器系统受到网络攻击的方式,避免服务器受到各种恶意攻击和网络威胁,那么,服务器硬防通常都会应用在哪些场景当中呢? 硬防服务器中一般会配备入侵检测系统和预防系统&#x…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...
如何应对敏捷转型中的团队阻力
应对敏捷转型中的团队阻力需要明确沟通敏捷转型目的、提升团队参与感、提供充分的培训与支持、逐步推进敏捷实践、建立清晰的奖励和反馈机制。其中,明确沟通敏捷转型目的尤为关键,团队成员只有清晰理解转型背后的原因和利益,才能降低对变化的…...
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章
用 Rust 重写 Linux 内核模块实战:迈向安全内核的新篇章 摘要: 操作系统内核的安全性、稳定性至关重要。传统 Linux 内核模块开发长期依赖于 C 语言,受限于 C 语言本身的内存安全和并发安全问题,开发复杂模块极易引入难以…...
【阅读笔记】MemOS: 大语言模型内存增强生成操作系统
核心速览 研究背景 研究问题:这篇文章要解决的问题是当前大型语言模型(LLMs)在处理内存方面的局限性。LLMs虽然在语言感知和生成方面表现出色,但缺乏统一的、结构化的内存架构。现有的方法如检索增强生成(RA…...
uniapp获取当前位置和经纬度信息
1.1. 获取当前位置和经纬度信息(需要配置高的SDK) 调用uni-app官方API中的uni.chooseLocation(),即打开地图选择位置。 <button click"getAddress">获取定位</button> const getAddress () > {uni.chooseLocatio…...
Neo4j 完全指南:从入门到精通
第1章:Neo4j简介与图数据库基础 1.1 图数据库概述 传统关系型数据库与图数据库的对比图数据库的核心优势图数据库的应用场景 1.2 Neo4j的发展历史 Neo4j的起源与演进Neo4j的版本迭代Neo4j在图数据库领域的地位 1.3 图数据库的基本概念 节点(Node)与关系(Relat…...
