【Android】四大组件之Service
目录
一、什么是Service
二、启停 Service
三、绑定 Service
四、前台服务
五、远程服务扩展
六、服务保活
七、服务启动方法混用
你可以把Service想象成一个“后台默默打工的工人”。它没有UI界面,默默地在后台干活,比如播放音乐、下载文件、处理网络请求等。即使你退出了App,Service也可以继续运行。
一、什么是Service
Service是Android应用的核心后台组件。
1. 无界面后台任务
- Service 是 Android 系统中无可视化界面、运行于后台的长生命周期组件。
- 核心功能:执行与用户界面无关的持续性任务,如后台播放音乐、文件下载等。
- Service 不依赖用户交互界面,生命周期独立于Activity。
- 典型应用场景:网络请求、传感器数据采集、跨进程通信(AIDL)。
2. 生命周期管理
Service有两种主要类型:
特性 | Started Service(启动式) | Bound Service(绑定式) |
---|---|---|
启动方式 | 通过 startService(Intent) 启动 | 通过 bindService(Intent, ServiceConnection, flags) 启动 |
生命周期 | onCreate() → onStartCommand() → onDestroy() | onCreate() → onBind() → onUnbind() → onDestroy() |
通信机制 | 无法直接与组件交互,需通过广播或 Intent 传递数据 | 通过 Binder 接口直接通信(支持方法调用) |
销毁条件 | 需手动调用 stopSelf() 或 stopService() | 所有绑定组件解绑后自动销毁 |
多组件绑定 | 不支持,每次启动独立运行 | 支持多个组件同时绑定(如多个 Activity 共享同一服务实例) |
适用场景 | 一次性后台任务(如下载、音乐播放) | 长期交互服务(如数据同步、实时计算) |
优先级与系统回收 | 后台服务可能被系统回收,可通过 startForeground() 提升为前台服务 | 优先级较低,绑定组件退出后可能更快被回收 |
共存场景 | 可与 Bound Service 共存,需同时调用 stopSelf() 和解绑操作才能销毁 | 与 Started Service 共存时,需先解绑所有组件再手动停止服务 |
涉及的生命周期方法:
生命周期方法 | 触发场景 |
---|---|
onCreate() | Service 首次创建时调用(仅一次) |
onStartCommand() | 每次通过 startService() 启动时调用 |
onBind() | 通过 bindService() 绑定时调用 |
onUnbind() | 所有客户端解绑时调用 |
onDestroy() | Service 被销毁前调用(需手动停止或系统回收) |
Service 默认运行在主线程,耗时操作需自行创建子线程或使用
IntentService
二、启停 Service
1. 定义 Service 类
继承 Service
类并实现核心方法:
public class MyService extends Service {private static final String TAG = "MyService";@Overridepublic IBinder onBind(Intent intent) {return null; // 非绑定模式时返回 null}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "Service 启动"); // 执行后台任务return START_STICKY; // 服务终止后自动重启}@Overridepublic void onDestroy() {Log.d(TAG, "Service 销毁");super.onDestroy();}
}
2. 注册 Service
在 AndroidManifest.xml
中添加声明:
<application><service android:name=".MyService" />
</application>
3. 通过 startService()
启动
在 Activity 或其他组件中调用:
Intent serviceIntent = new Intent(this, MyService.class);
startService(serviceIntent); // 启动服务:ml-citation{ref="6,8" data="citationList"}
4. 通过 stopService()
或 stopSelf()
停止
stopService(new Intent(this, MyService.class)); // 外部停止
// 或在 Service 内部调用 stopSelf();:ml-citation{ref="6,8" data="citationList"}
三、绑定 Service
1. 定义 Bound Service
- 通过
LocalBinder
返回 Service 实例,实现组件间交互 onBind()
返回IBinder
对象,供客户端绑定
// MyBoundService.java
public class MyBoundService extends Service { private final IBinder binder = new LocalBinder(); private static final String TAG = "MyBoundService"; public class LocalBinder extends Binder { MyBoundService getService() { return MyBoundService.this; } } @Override public IBinder onBind(Intent intent) { Log.d(TAG, "Service 已绑定"); return binder; } @Override public boolean onUnbind(Intent intent) { Log.d(TAG, "所有客户端已解绑"); return super.onUnbind(intent); } // 自定义服务方法(供Activity调用) public void performTask(String data) { Log.d(TAG, "执行任务:" + data); }
}
2. 注册 Service
在 AndroidManifest.xml
中添加声明:
<application> <service android:name=".MyBoundService" />
</application>
3. Activity 绑定与通信
- 通过
bindService()
建立绑定 ServiceConnection
处理绑定成功/断开事件- 绑定后通过
myService
实例直接调用服务方法 - 必须调用
unbindService()
释放资源,避免内存泄漏 - 多个组件可绑定同一服务,全部解绑后服务销毁
// MainActivity.java
public class MainActivity extends AppCompatActivity { private MyBoundService myService; private boolean isBound = false; private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { MyBoundService.LocalBinder binder= (MyBoundService.LocalBinder) service; myService = binder.getService(); isBound = true; myService.performTask("Hello from Activity!"); // 调用服务方法 } @Override public void onServiceDisconnected(ComponentName name) { isBound = false; } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定服务 Intent intent = new Intent(this, MyBoundService.class); bindService(intent, connection, Context.BIND_AUTO_CREATE); } @Override protected void onDestroy() { super.onDestroy(); if (isBound) { unbindService(connection); // 必须解绑避免泄漏 isBound = false; } }
}
Activity 创建时: bindService() → Service: onCreate() → onBind()
Activity 销毁时: unbindService() → Service: onUnbind() → onDestroy()
四、前台服务
1. 服务端实现
- Android 8.0+ 必须创建
NotificationChannel
,否则通知无法显示 - 通过
IMPORTANCE_LOW
设置低优先级(无提示音) startForeground()
必须在onCreate()
或onStartCommand()
中调用,调用后服务优先级提升,避免被系统轻易回收stopForeground(true)
确保通知栏通知被移除
// ForegroundService.java
public class ForegroundService extends Service {private static final int NOTIFICATION_ID = 1001;private static final String CHANNEL_ID = "foreground_service_channel";@Overridepublic void onCreate() {super.onCreate();createNotificationChannel();startForegroundWithNotification("服务初始化中...");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 获取 Activity 传递的数据(可选)String inputData = intent != null? intent.getStringExtra("input_data") : null;updateNotification("正在运行: " + inputData);// 模拟耗时任务new Thread(() -> {for (int i = 0; i < 10; i++) {try {Thread.sleep(1000);updateNotification("进度: " + (i + 1) * 10 + "%");} catch (InterruptedException e) {e.printStackTrace();}}stopSelf(); // 任务完成后自动停止服务}).start();return START_STICKY; // 服务被系统杀死后自动重启}private void createNotificationChannel() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {NotificationChannel channel = new NotificationChannel(CHANNEL_ID,"前台服务示例",NotificationManager.IMPORTANCE_LOW);channel.setDescription("用于展示前台服务的持续运行状态");NotificationManager manager= getSystemService(NotificationManager.class);manager.createNotificationChannel(channel);}}private void startForegroundWithNotification(String text) {Intent notificationIntent = new Intent(this, MainActivity.class);PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,PendingIntent.FLAG_IMMUTABLE);Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID).setContentTitle("前台服务示例").setContentText(text).setSmallIcon(R.drawable.ic_notification).setContentIntent(pendingIntent).setOnlyAlertOnce(true) // 避免重复提示音.build();startForeground(NOTIFICATION_ID, notification);}private void updateNotification(String text) {Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID).setContentTitle("前台服务示例").setContentText(text).setSmallIcon(R.drawable.ic_notification).setOnlyAlertOnce(true).build();NotificationManager manager= getSystemService(NotificationManager.class);manager.notify(NOTIFICATION_ID, notification);}@Overridepublic IBinder onBind(Intent intent) {return null; // 无需绑定功能}@Overridepublic void onDestroy() {super.onDestroy();stopForeground(true); // 停止时移除通知}
}
2. 配置清单文件注册服务
<!-- 服务端 AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"><!-- 必须的权限声明,否则startForeground方法不可用 --><uses-permission android:name="android.permission.FOREGROUND_SERVICE"/><application><!-- 服务定义 --><serviceandroid:name=".ForegroundService"android:enabled="true"android:exported="false"android:foregroundServiceType="mediaPlayback"/> <!-- 按需配置类型 --></application>
</manifest>
3. 客户端调用(Activity)
- 通过
stopSelf()
或stopService()
停止服务
// MainActivity.java
public class MainActivity extends AppCompatActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 启动前台服务按钮findViewById(R.id.btn_start).setOnClickListener(v -> {Intent serviceIntent = new Intent(this, ForegroundService.class);serviceIntent.putExtra("input_data", "用户启动任务");if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {startForegroundService(serviceIntent); // Android 8.0+ 专用方法} else {startService(serviceIntent);}});// 停止服务按钮findViewById(R.id.btn_stop).setOnClickListener(v -> {Intent serviceIntent = new Intent(this, ForegroundService.class);stopService(serviceIntent);});}
}
4. 客户端配置权限
<!-- 客户端 AndroidManifest.xml -->
<manifest> <!-- 添加权限 --> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <!-- 跨进程调用时添加(可选) --> <queries> <package android:name="com.example.service"/> </queries> <application> <!-- 无需声明服务组件 --> </application>
</manifest>
五、远程服务扩展
1. 自定义 Parcelable 对象
// CustomData.java
package com.example.model; import android.os.Parcel;
import android.os.Parcelable; public class CustomData implements Parcelable { private String content; // 构造函数 public CustomData(String content) { this.content = content; } // Parcelable 反序列化构造函数 protected CustomData(Parcel in) { content = in.readString(); } // Parcelable CREATOR public static final Creator<CustomData> CREATOR = new Creator<CustomData>() { @Override public CustomData createFromParcel(Parcel in) { return new CustomData(in); } @Override public CustomData[] newArray(int size) { return new CustomData[size]; } }; @Override public int describeContents() { return 0; } @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(content); } // Getter public String getContent() { return content; }
}
2. 定义 AIDL 接口
- AIDL 文件定义跨进程通信的接口方法
- 支持基本类型、
String
、List
、Parcelable
等数据类型 - 需在 AIDL 中显式导入
parcelable
类型
// IRemoteService.aidl
package com.example.service; parcelable CustomData;
interface IRemoteService { int add(int a, int b); String getData(String input); void sendData(in CustomData data); void registerCallback(IRemoteCallback callback);void unregisterCallback(IRemoteCallback callback);
} // 回调接口(IRemoteCallback.aidl)
interface IRemoteCallback {void onResult(int result);
}
3. 服务端实现 AIDL 接口
- 继承
IRemoteService.Stub
实现接口方法 - 通过
onBind()
返回IBinder
对象 - 直接使用
CustomData
对象(已自动反序列化) - 服务端通过
RemoteCallbackList
自动清理无效回调,无需手动处理。 RemoteCallbackList.register()
会自动去重,多次注册同一回调不会重复触发
public class RemoteService extends Service { private final IBinder binder = new RemoteBinder();// 使用 RemoteCallbackList 管理跨进程回调(线程安全)private final RemoteCallbackList<IRemoteCallback> callbackList= new RemoteCallbackList<>();private class RemoteBinder extends IRemoteService.Stub { @Override public int add(int a, int b) { int result = a + b;notifyResult(result); // 触发回调通知return result;} @Override public String getData(String input) { return "Processed: " + input; } @Override public void sendData(CustomData data) throws RemoteException { Log.d(TAG, "收到数据: " + data.getContent()); // 处理数据逻辑 } @Overridepublic void registerCallback(IRemoteCallback callback) {if (callback != null) {callbackList.register(callback);}}@Overridepublic void unregisterCallback(IRemoteCallback callback) {if (callback != null) {callbackList.unregister(callback);}}// 通知所有客户端计算结果private void notifyResult(int result) {int count = callbackList.beginBroadcast();try {for (int i = 0; i < count; i++) {IRemoteCallback callback = callbackList.getBroadcastItem(i);callback.onResult(result); // 跨进程回调}} catch (RemoteException e) {e.printStackTrace(); // 客户端已断开,自动从列表中移除} finally {callbackList.finishBroadcast();}}} @Override public IBinder onBind(Intent intent) { return binder; } @Overridepublic void onDestroy() {super.onDestroy();callbackList.kill(); // 清理回调列表}
}
注意:必须使用 Android 提供的
RemoteCallbackList
管理跨进程回调(自动处理客户端进程死亡情况),普通集合(如ArrayList
)无法正确识别跨进程的IBinder
对象。
4. 注册 Service(AndroidManifest.xml)
android:exported="true"
允许跨进程访问- 定义唯一
action
供客户端绑定 - android:process=":remote" 强制指定独立进程,所有跨进程绑定均指向此进程,复用同一实例
<!-- 服务端AndroidManifest.xml-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"><!-- 声明自定义权限(可选,用于安全控制) --><permissionandroid:name="com.example.permission.REMOTE_SERVICE"android:protectionLevel="signature"/> <!-- 仅允许同签名应用访问 --><!-- 添加前台服务权限(若涉及前台服务) --><uses-permission android:name="android.permission.FOREGROUND_SERVICE"/><application><!-- RemoteService 定义 --><serviceandroid:name=".RemoteService"android:enabled="true"android:exported="true" <!-- 允许跨进程访问 -->android:permission="com.example.permission.REMOTE_SERVICE" <!-- 绑定权限 -->android:process=":remote"> <!-- 指定独立进程,全局唯一 --><intent-filter><action android:name="com.example.service.IRemoteService"/></intent-filter></service></application>
</manifest>
5. 客户端绑定与调用远程服务
- 通过隐式 Intent 指定服务端包名和 Action
- 使用
IRemoteService.Stub.asInterface()
转换IBinder
对象 - 所有跨进程方法调用需处理
RemoteException
- 在
onServiceDisconnected()
和onBindingDied()
中,直接清理本地资源(如置空remoteService
),不调用任何远程方法。 - 客户端无需在断开时调用
unregisterCallback()
,服务端能正确处理死亡 Binder,其注册的回调会自动从列表中移除。 - 如果客户端维护了本地回调列表(如
localCallbackList
),需在断开时直接清理,无需依赖服务端确认。
public class MainActivity extends AppCompatActivity { private IRemoteService remoteService; private boolean isBound = false; private IRemoteCallback callback = new IRemoteCallback.Stub() {@Overridepublic void onResult(int result) {// 注意:此处运行在 Binder 线程,需切到主线程更新 UInew Handler(Looper.getMainLooper()).post(() -> {textView.setText("计算结果: " + result);});}};// 绑定服务方法(封装复用)private void bindService() {Intent intent = new Intent("com.example.service.IRemoteService");intent.setPackage("com.example.service"); // 显式指定包名// 判断是否 Android 11+ 需要添加 flagsif (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {bindService(intent, connection,Context.BIND_AUTO_CREATE | Context.BIND_IMPORTANT);} else {bindService(intent, connection, Context.BIND_AUTO_CREATE);}}private ServiceConnection connection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { remoteService = IRemoteService.Stub.asInterface(service); isBound = true; try { remoteService.registerCallback(callback); // 注册回调int result = remoteService.add(3, 5); Log.d("Client", "Result: " + result); CustomData data = new CustomData("Hello from Client"); remoteService.sendData(data);} catch (RemoteException e) { // 远程调用异常捕获e.printStackTrace(); Log.e("Client", "Remote call failed: " + e.getMessage());} } @Override public void onServiceDisconnected(ComponentName name) { isBound = false; remoteService = null; if (reconnectAttempts < MAX_RECONNECT_ATTEMPTS) {new Handler(Looper.getMainLooper()).postDelayed(() -> {reconnectAttempts++;Log.w(TAG, "尝试第 " + reconnectAttempts + " 次重连...");bindService(); // 调用绑定方法}, 3000); // 延迟 3 秒后重试(避免频繁请求)} else {Log.e(TAG, "已达到最大重连次数,停止尝试");}} @Overridepublic void onBindingDied(ComponentName name) {// Android 10+ 新增回调,处理绑定失效场景onServiceDisconnected(name);}}; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); bindService(); } @Override protected void onDestroy() { super.onDestroy(); try {if (remoteService != null && callback != null) {remoteService.unRegisterCallback(callback); // 主动注销remoteService = null;}} catch (RemoteException e) {e.printStackTrace();}if (isBound) { unbindService(connection); isBound = false; } }
}
6. 客户端声明权限
<!-- 客户端 AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"package="com.example.client"><!-- Android 11+ 跨应用通信需添加 queries(必选) --><queries><!-- 声明目标服务端包名 --><package android:name="com.example.service" /><!-- 若需要调用特定组件(如 Activity)可扩展为 --><!--<intent><action android:name="android.intent.action.VIEW" /><data android:scheme="https" /></intent>--></queries><application><!-- 其他组件声明(如 Activity) --></application>
</manifest>
六、服务保活
方法 | 适用场景 | 厂商兼容性 | 系统限制 |
---|---|---|---|
前台服务+通知 | 用户感知型任务 | 高 | Android 8+ |
JobScheduler 定时拉活 | 低频后台任务 | 中 | Android 5+ |
系统广播监听 | 紧急恢复场景 | 低 | Android 7+ |
独立进程守护 | 高稳定性要求场景 | 中 | 全版本 |
1. 前台服务 + 通知 (前面已介绍)
- 使用
startForeground()
提升服务优先级至前台级别 - Android 9+ 需动态申请
FOREGROUND_SERVICE
权限
public class PersistentService extends Service {@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 创建前台通知(Android 8.0+ 需通知渠道)Notification notification = new NotificationCompat.Builder(this, "channel_id").setContentTitle("服务运行中").setSmallIcon(R.drawable.ic_notification).build();startForeground(1, notification); // 必须显示通知return START_STICKY; // 服务终止后尝试重启:// ml-citation{ref="1,6" data="citationList"}}
}
2. 粘性服务重启策略
覆盖生命周期方法:
@Override
public void onTaskRemoved(Intent rootIntent) {// 任务被移除时(如用户划掉最近任务)触发重启Intent restartIntent = new Intent(this, PersistentService.class);restartIntent.setPackage(getPackageName());startService(restartIntent);super.onTaskRemoved(rootIntent);
}@Override
public void onDestroy() {// 服务被系统杀死时触发重启逻辑// 发送广播,需要注册一个广播接收器sendBroadcast(new Intent("RESTART_SERVICE_ACTION")); super.onDestroy();
}
注册广播接收器,通过广播重新拉起服务 :
<receiver android:name=".RestartReceiver"><intent-filter><action android:name="RESTART_SERVICE_ACTION" /></intent-filter>
</receiver>
频繁调用
startService()
可能导致 ANR,建议结合JobScheduler
优化
3. 系统广播监听
听高频触发广播,利用网络变化、解锁等事件触发服务重启。
<receiver android:name=".SystemEventReceiver"><intent-filter><action android:android:name="android.intent.action.BOOT_COMPLETED" /><action android:name="android.net.conn.CONNECTIVITY_CHANGE" /><action android:name="android.intent.action.USER_PRESENT" /></intent-filter>
</receiver>
4. 进程守护与JobScheduler
独立进程运行,减少主进程崩溃对服务的影响。
<service android:name=".PersistentService"android:process=":persistent_process" />
JobScheduler 定时唤醒,定期检查服务状态并拉起。
ComponentName serviceComponent = new ComponentName(this, PersistentService.class);
JobInfo jobInfo = new JobInfo.Builder(1, serviceComponent).setPeriodic(15 * 60 * 1000) // 15分钟间隔.setPersisted(true) // 设备重启后保持任务.build();
JobScheduler scheduler = (JobScheduler) getSystemService(JOB_SCHEDULER_SERVICE);
scheduler.schedule(jobInfo);
七、服务启动方法混用
1. startService()
重复调用
- 首次调用:触发
onCreate()
→onStartCommand()
- 后续调用:仅触发
onStartCommand()
,onCreate()
不再执行
// 第一次调用
startService(intent); // onCreate() -> onStartCommand()// 第二次调用
startService(intent); // 仅 onStartCommand()
2. bindService()
重复调用
- 首次绑定:触发
onCreate()
→onBind()
- 后续绑定:若 Service 已存在,直接返回已创建的
IBinder
对象,不再触发onBind()
// 第一次绑定
// onCreate() -> onBind()
bindService(intent, conn, BIND_AUTO_CREATE); // 第二次绑定(同一进程)
// 无生命周期方法调用,复用已有 IBinder
bindService(intent, conn2, BIND_AUTO_CREATE);
不同进程再次绑定:
- 同一 Service 实例:若
Service
已在独立进程运行,后续绑定直接复用已有实例,不再触发onCreate()
和onBind()
,仅通过ServiceConnection
返回IBinder
代理对象。- 新 Service 实例:若应用配置多进程且未声明
android:process
,不同组件进程可能触发多个Service
实例(需避免此设计)
3. 混合调用场景
startService()
后 bindService():
Service 生命周期持续到 unbindService()
和 stopService()
/stopSelf()
均被调用
startService(intent); // onCreate() -> onStartCommand()
bindService(intent, conn); // onBind(),Service 已存在无需创建
同理,先bindService()后startService()
bindService(intent, conn); // 创建 Service 实例,onCreate() → onBind()
startService(intent); // onStartCommand(),Service 已存在无需创建
混合调用时需同时调用
stopService()
和unbindService()
才能销毁 Service
相关文章:
【Android】四大组件之Service
目录 一、什么是Service 二、启停 Service 三、绑定 Service 四、前台服务 五、远程服务扩展 六、服务保活 七、服务启动方法混用 你可以把Service想象成一个“后台默默打工的工人”。它没有UI界面,默默地在后台干活,比如播放音乐、下载文件、处理…...
VO包装类和实体类分别是什么?区别是什么?
VO包装类和实体类 1. 实体类(Entity Class)是什么?2. VO包装类(Value Object Class)是什么?3. VO包装类和实体类的区别4. 实际应用中的区别5. 举例5.1. 实体类(Entity Class)的定义与…...
如何创建一个C#项目(基于VS2022版)
一.先找到要保存项目的位置,新建一个文件夹 二.打开VisualStudio,选择创建新项目 三.选择模版: 选择操作语言和操作系统 这个是跨平台的 初学在windows系统上,可选择其他,下面这个是不带窗体模版 也可根据需要选择带窗体模版 点击下一步 填写项目名称,选择项目保存位置,填写解…...
RabbitMQ 四种交换机(Direct、Topic、Fanout、Headers)详解
本文是博主在梳理 RabbitMQ 知识的过程中,将所遇到和可能会遇到的基础知识记录下来,用作梳理 RabbitMQ 的整体架构和功能的线索文章,通过查找对应的知识能够快速的了解对应的知识而解决相应的问题。 文章目录 一、直连交换机(Dire…...
聚合分销系统开发:短剧小说外卖网盘电商cpscpa系统
聚合分销系统是一种整合了多种分销项目和功能的综合性平台,其核心在于通过CPS(按销售付费)和CPA(按行为付费)两种模式,为推广者提供多样化的赚钱机会。以下是聚合分销系统的主要项目和功能: 一…...
【Flume 】Windows安装步骤、配置环境
🛠 Flume 是什么? Apache Flume 是一个高效、可靠、可扩展的数据收集系统,通常用于收集日志、流数据,比如收集数据到 HDFS、Kafka 等。 虽然 Flume 本身是为 Linux 服务器设计的,但 在 Windows 本地也是能跑起来的&a…...
【信息系统项目管理师】高分论文:论质量管理和进度管理(智慧旅游平台建设项目)
更多内容请见: 备考信息系统项目管理师-专栏介绍和目录 文章目录 论文1、规划质量管理2、质量保证3、质量控制论文 2019年3月,我作为项目经理,参加了某市智慧旅游平台建设项目,负责项目的全面管理, 该项目以打造一流的国内外生态旅游城市为目标,旨在大数据云平台建设的基…...
一致性哈希详解:优雅地扩展分布式系统
引言 对于哈希算法,相信大家一定不会陌生。它经常被用在负载均衡、分库分表等场景中。例如,在进行分库分表时,我们可能初步根据业务分析,确定 128 张表足以满足当前的数据量需求。此时,当需要插入或查询一条记录时&am…...
pytest 技术总结
目录 一 pytest的安装: 二 pytest有三种启动方式: 三 用例规则: 四 配置框架: 一 pytest的安装: pip install pytest # 安装 pip install pytest -U # 升级到最新版 二 pytest有三种启动方式: 1…...
数据库MySQL学习——day5(总结与复习实践)
文章目录 1、复习总结1.1. 数据库基础1.2. 表操作1.3. 数据操作1.4. 更新与删除 2、实践任务:创建学生管理系统数据库2.1. 数据库设计2.2. 创建表的SQL语句2.3. 插入示例数据2.4. 查询与数据操作示例 3、调试与练习4、 今日小结 1、复习总结 1.1. 数据库基础 数据…...
unity bug
发现一个奇怪的bug,就是某些unity版本打包apk时候不允许StreamingAssets里面有中文文件或者中文路径。比如下图这面这俩都是不行的。 解决方案:中文改为英文即可。 一般报错信息如下: > Configure project :launcher WARNING:The option s…...
苹果计划2026年底前实现美版iPhone“印度造”,以减轻关税及地缘政治风险
基于 6 个来源 据多家媒体报道,苹果公司计划在2026年底前,实现在印度组装销往美国的大部分或全部iPhone手机,以减轻关税和地缘政治紧张局势带来的风险。这一目标意味着苹果需将印度的iPhone产量增加一倍以上,凸显其供应链多元化战…...
新增Webhook通知功能,文档目录树展示性能优化,zyplayer-doc 2.5.1 发布啦!
zyplayer-doc是一款适合企业和个人使用的WIKI知识库管理工具,支持在线编辑富文本、Markdown、表格、Office文档、API接口、思维导图、Drawio以及任意的文本文件,支持基于知识库的AI问答,专为私有化部署而设计,最大程度上保证企业或…...
【量化交易笔记】17.多因子的线性回归模型策略
前言 上一篇介绍了 因子的评价和分析方法,让我知道如何判断该因子的作用,以及对最终结果的影响,其最大的问题,他只能评价和分析单因子,而对多个因子,不能直接加以评价。我们自然会想到,如果是多…...
五年经验Java开发如何破局创业
🤟致敬读者 🟩感谢阅读🟦笑口常开🟪生日快乐⬛早点睡觉📘博主相关 🟧博主信息🟨博客首页🟫专栏推荐🟥活动信息文章目录 五年经验Java开发如何破局创业一、创业方向筛选与优劣势分析**方向1:技术教育/在线课程开发****方向2:企业级技术服务外包****方向3:技…...
定制一款国密浏览器(11):SM2算法的椭圆曲线参数定义
在国密算法中,SM2 算法是最复杂的,不仅是算法本身比较复杂,其应用场景也复杂。不管 SM2 算法本身有多复杂,作为开发者,我们需要知道的是 SM2 算法是建立在椭圆曲线算法(ECC)之上。关于 SM2 算法和椭圆曲线算法之间的关系,参考我之前的一篇文章: 解读国密非对称加密算…...
RAG技术与应用---0426
大语言模型>3.10 课程中会用到python 工具箱: faiss,modelscope,langchain,langchain_community,PyPDF2 1)大模型应用开发的三种模式 提示词没多少工作量,微调又花费时间费用,RAG是很多公司招聘用来对LLM进行应用…...
STM32的开发环境介绍
目录 STM32软件环境 Keil软件在线安装 其他软件环境安装 STM32开发的几种方式 STM32寄存器版本和库函数版本 标准外设库的作用: STM32软件环境 STM32 的集成开发环境(IDE):编辑编译软件 常见的环境: (1)KEIL&a…...
【生成式AI】从原理到实践的创造性革命
目录 前言技术背景与价值当前技术痛点解决方案概述目标读者说明 一、技术原理剖析核心概念图解核心作用讲解关键技术模块说明技术选型对比 二、实战演示环境配置要求核心代码实现(文生图) 三、性能对比测试方法论量化数据对比结果分析 四、最佳实践推荐方…...
Win下Pycharm运行/调试配置脚本形参执行替换Linux下终端执行,进行调试需要注意的
Linux下终端执行 python demo/image_demo.py demo/demo.jpg rtmdet_tiny_8xb32-300e_coco.py --weights rtmdet_tiny_8xb32-300e_coco_20220902_112414-78e30dcc.pth --device cpuWin下Pycharm运行/调试配置脚本形参执行 主要改红色两处 如果工作目录正确,脚本形参…...
Pytorch(无CPU搭建)+Jupyter
2024年最新最简洁深度学习环境配置:AnacondaPyTorch(CPU、GPU)VScodePycahrm_哔哩哔哩_bilibili 跟 PyCharm說再見, [VSCode] PythonJupyter 超牛逼的功能 ! 5分鐘大幅提升編碼效率~ 數據分析、AI大神必備_哔哩哔哩_bilibili...
类的高级特性与语法细节
static 静态关键字 Java中的static关键字用于修饰类的成员(属性或方法),表示“静态”的含义,即属于类本身,而非某个对象。静态成员在内存中只有一份,在类加载时初始化,生命周期贯穿程序运行始终…...
基于 RAG 的 Text2SQL 全过程的 Python 实现详解,结合 LangChain 框架实现自然语言到 SQL 的转换
什么是RAG 一、核心流程:三阶段协同 RAG的核心流程分为检索(Retrieval)、增强(Augmentation)、生成(Generation)三个阶段,形成“检索→知识整合→生成”的闭环。 1. 检索ÿ…...
使用 OpenCV 进行视觉图片调整的几种常见方法
以下是使用 OpenCV 进行视觉图片调整的几种常见方法: 调整图片大小 指定目标尺寸:使用cv2.resize()函数,通过设定目标图像的宽度和高度来调整图片大小。例如,将图片调整为 200x200 像素: import cv2 image cv2.imre…...
【特殊场景应对9】视频简历的适用场景与风险分析
写在最前 作为一个中古程序猿,我有很多自己想做的事情,比如埋头苦干手搓一个低代码数据库设计平台(目前只针对写java的朋友),比如很喜欢帮身边的朋友看看简历,讲讲面试技巧,毕竟工作这么多年,也做到过高管,有很多面人经历,意见还算有用,大家基本都能拿到想要的offe…...
Dify 1.3.0 为 LLM 节点引入了结构化输出支持
Dify 1.3.0 为 LLM 节点引入了结构化输出支持 0. 引言1. 使用方法 0. 引言 Dify 1.3.0 开始,在 LLM 节点支持结构化输出:Dify 已经为 LLM 节点引入了结构化输出支持。这意味着您的语言模型现在可以返回整齐组织且易于处理的数据。后端实现由 Nov1c444 在…...
【Linux网络】HTTP协议全解析 - 从请求响应到方法与Header
📢博客主页:https://blog.csdn.net/2301_779549673 📢博客仓库:https://gitee.com/JohnKingW/linux_test/tree/master/lesson 📢欢迎点赞 👍 收藏 ⭐留言 📝 如有错误敬请指正! &…...
JSP实现用户登录注册系统(三天内自动登录)
JSP实现用户登录注册系统 引言 在Web开发中,用户认证是最基础且核心的功能之一。本文基于JSP技术,实现了一个包含注册、登录、自动登录(3天内)、退出等功能的用户系统,并在过程中解决了Cookie字符错误、错误信息回显…...
大数据模型现状分析
大数据模型现状分析 一、引言 在当今数字化时代,数据以前所未有的速度增长,大数据已成为推动各行业发展的核心动力。大数据模型作为挖掘数据价值的关键工具,正受到广泛关注与深入研究。通过对海量、多样且高速产生的数据进行处理和分析&…...
代码随想录算法训练营第二十八天
LeetCode题目: 509. 斐波那契数70. 爬楼梯746. 使用最小花费爬楼梯2444. 统计定界子数组的数目(每日一题) 其他: 今日总结 往期打卡 动态规划解题步骤: 确定递推公式确定遍历顺序记忆化搜索(确定dp数组以及下标的含义与初始化值)递推优化与空间优化 509. 斐波那契数 跳转: 5…...
HTML与安全性:XSS、防御与最佳实践
HTML 与安全性:XSS、防御与最佳实践 前言 现代 Web 应用程序无处不在,而 HTML 作为其基础结构,承载着巨大的安全责任。跨站脚本攻击(XSS)仍然是 OWASP Top 10 安全威胁之一,对用户数据和网站完整性构成严…...
三维重建(二十)——思路整理与第一步的进行
文章目录 一、整体思路二、细分三、之前存在问题四、任务安排五、第一步——找到内参并选定一种5.1 train的RTK5.2 test的RTK5.3 各选择一个5.3.1 train-185.3.2 test-193一、整体思路 这部分主要是宏观的讲一下整体框架。 从gshell里面提取核心参数,放入py3d,渲染出图片,…...
判断 ONNX 模型是否支持 GPU
🔍 判断 ONNX 模型是否支持 GPU 的几个关键点: ✅ 1. 检查模型支持的 Execution Provider 可以通过下面的代码打印出来当前模型使用了什么设备: 需要安装好:onnxruntime-gpu import onnxruntime as ort session ort.InferenceSe…...
CANFD技术在实时运动控制系统中的应用:协议解析、性能测试与未来发展趋势
摘要: 本文深入探讨了CANFD技术在实时运动控制系统中的应用。通过对传统CAN协议与CANFD协议的对比分析,详细阐述了CANFD在提升数据传输效率、增强系统实时性与稳定性方面的优势。文章结合具体测试案例,对CANFD总线的性能指标进行了全面评估&a…...
Java基础 4.26
1.访问修饰符细节 package com.logic.modifier;public class A {public int n1 100;protected int n2 200;int n3 300;private int n4 400;public void m1() {//在同一个类中 可以访问public protected 默认 private 修饰属性和方法System.out.println(n1 " " …...
山东大学离散数学第九章习题解析
参考教材:离散数学教程,徐秋亮 / 栾俊峰 / 卢雷 / 王慧 / 赵合计 编著,山东大学计算机科学与技术学院 注:该解析为个人所写,涵盖了 2022-2023-2 学期赵合计老师所布置的所有课本习题;由于学识、认识及经验…...
5G融合消息PaaS项目深度解析 - Java架构师面试实战
5G融合消息PaaS项目深度解析 - Java架构师面试实战 场景:互联网大厂Java求职者面试,面试官针对5G融合消息PaaS项目进行提问。 第一轮提问 面试官:马架构,请简要介绍5G融合消息PaaS平台的核心功能和应用场景。 马架构ÿ…...
React-Redux
1、安装 npm i redux react-redux reduxjs/toolkit 2、基础使用方式(无 Toolkit) (1)核心Api createStore:创建数据仓库;store.dispatch():用于派发action,执行修改动作…...
Linux基础篇、第4章_03系统磁盘高级管理LVM 逻辑卷管理器
题目:系统磁盘高级管理LVM 逻辑卷管理器 版本号: 1.0,0 作者: 老王要学习 日期: 2025.04.26 适用环境: Centos7 文档说明 本文档聚焦于 Centos7 系统下的磁盘高级管理,围绕 LVM 逻辑卷管理器展开。详细介绍了物理卷、卷组和逻辑卷的创建、管理与删除操…...
代码随想录算法训练营Day36
力扣1049.最后一块石头的重量Ⅱ【medium】 力扣474.一和零【meidum】 一、力扣1049.最后一块石头的重量Ⅱ【medium】 题目链接:力扣1049.最后一块石头的重量Ⅱ 视频链接:代码随想录 1、思路 把这个问题转换成尽可能将 stones 分成两个等分子集…...
iperf网络性能测试
iperf 是一个网络性能测试工具,用于测量网络带宽、延迟、抖动等性能指标。它支持 TCP 和 UDP 协议,可以在客户端和服务器模式下运行,广泛用于网络性能评估和故障排查。 主要功能 带宽测试:测量网络的最大可用带宽。延迟测试&…...
基于 Nginx 的 WebSocket 反向代理实践
一、HTTP 协议升级机制回顾 Upgrade/Connection 报头 客户端发起 WebSocket 握手时,会在普通 HTTP 请求中加入Upgrade: websocket Connection: Upgrade Sec-WebSocket-Key: <随机值> Sec-WebSocket-Version: 13服务端若接受协议切换,会以 101 Swit…...
C++ 同步原语
同步原语(Synchronization Primitives)是操作系统和编程语言提供的基本工具,用于在多线程或并发环境中协调线程(或进程)之间的执行顺序,管理共享资源的访问,以避免数据竞争(data rac…...
mmap详解
mmap详解 mmap基础概念mmap内存映射原理mmap相关函数调用mmap的使用细节mmap和常规文件操作的区别 mmap基础概念 mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间,实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一…...
基于大模型底座重构司法信息系统
前置篇章:法律智能体所需的基础知识 构建一个高效的法律智能体,特别是在基于RAG(Retrieval-Augmented Generation)架构的背景下,需要融合多种学科和领域的知识。以下是对法律智能体开发和应用所需核心基础知识的简要介…...
如何判断你的PyTorch是GPU版还是CPU版?
如何判断你的PyTorch是GPU版还是CPU版? PyTorch作为当前最流行的深度学习框架之一,支持在CPU和GPU(NVIDIA CUDA)上运行。对于深度学习开发者来说,正确识别PyTorch版本至关重要,因为GPU版本可以带来10-100倍的性能提升。本文将全面…...
Leetcode刷题记录19——无重复字符的最长子串
题源:https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/?envTypestudy-plan-v2&envIdtop-100-liked 题目描述: 思路一: 通过两个指针,第一个指针指向字串的开头,第二…...
SpringBoot程序的创建以及特点,配置文件,LogBack记录日志,配置过滤器、拦截器、全局异常
一、创建一个SpringBoot程序 在之前写过一篇如何创建SpringBoot程序,两种方式,方法1:通过maven创建SpringBoot项目 方法2:使用Spring Initialzr创建一个SpringBoot项目(缺点:当创建项目时网络中断&#x…...
Ubuntu20.04 Ollama 配置相关
Ubuntu20.04 Ollama 配置相关 Ubuntu20.04 Ollama 配置相关ollama修改配置文件常用命令修改端口局域网访问 Ubuntu20.04 Ollama 配置相关 ollama修改配置文件常用命令 sudo gedit /etc/systemd/system/ollama.service systemctl daemon-reload systemctl restart ollama sys…...
python调用ffmpeg对截取视频片段,可批量处理
本文完全免费,非VIP文章,如果您发现需VIP可看全文,请邮箱联系我:openwebsitefoxmail.com 文章目录 python调用ffmpeg对截取视频片段,可批量处理用到的ffmpeg命令python调用bash指令的方法python处理代码准备函数python…...