当前位置: 首页 > article >正文

【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 文件定义跨进程通信的接口方法
  • 支持基本类型、StringListParcelable 等数据类型
  • 需在 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界面&#xff0c;默默地在后台干活&#xff0c;比如播放音乐、下载文件、处理…...

TRO再添新案 TME再拿下一热门IP,涉及Paddington多个商标

4月2日和4月8日&#xff0c;TME律所代理Paddington & Company Ltd.对热门IP Paddington Bear帕丁顿熊的多类商标发起维权&#xff0c;覆盖文具、家居用品、毛绒玩具、纺织用品、游戏、电影、咖啡、填充玩具等领域。跨境卖家需立即排查店铺内的相关产品&#xff01; 案件基…...

spring-session-data-redis使用

spring-session-data-redis是spring session项目中的一个子模块&#xff0c;&#xff0c;他允许你使用Redis来存储http session&#xff0c;&#xff0c;从而支持多个应用实例之间共享session&#xff0c;&#xff0c;&#xff0c;即分布式session 原理&#xff1a; EnableRed…...

图论---LCA(倍增法)

预处理 O( n logn )&#xff0c;查询O( log n ) #include<bits/stdc.h> using namespace std; typedef pair<int,int> pii; const int N40010,M2*N;//是无向边&#xff0c;边需要见两边int n,m; vector<int> g[N]; //2的幂次范围 0~15 int depth[N],fa[N][1…...

WPF实现类似Microsoft Visual Studio2022界面效果及动态生成界面技术

WPF实现类似VS2022界面效果及动态生成界面技术 一、实现类似VS2022界面效果 1. 主窗口布局与主题 <!-- MainWindow.xaml --> <Window x:Class"VsStyleApp.MainWindow"xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x…...

【安全扫描器原理】网络扫描算法

【安全扫描器原理】网络扫描算法 1.非顺序扫描2.高速扫描 & 分布式扫描3.服务扫描 & 指纹扫描 1.非顺序扫描 参考已有的扫描器&#xff0c;会发现几乎所有的扫描器都无一例外地使用增序扫描&#xff0c;即对所扫描的端口自小到大依次扫描&#xff0c;殊不知&#xff0…...

WPF之项目创建

文章目录 引言先决条件创建 WPF 项目步骤理解项目结构XAML 与 C# 代码隐藏第一个 "Hello, WPF!" 示例构建和运行应用程序总结相关学习资源 引言 Windows Presentation Foundation (WPF) 是 Microsoft 用于构建具有丰富用户界面的 Windows 桌面应用程序的现代框架。它…...

Unity中数据储存

在Unity项目开发中,会有很多数据,有需要保存到本地的数据,也有直接保存在缓存中的临时数据,一般为了方便整个项目框架中各个地方能调用需要的数据,因此都会实现一个数据工具或者叫数据管理类,用来管理项目中所有的数据。 首先保存在缓存中的数据,比如用户信息,我们只需…...

第十一天 主菜单/设置界面 过场动画(Timeline) 成就系统(Steam/本地) 多语言支持

前言 对于刚接触Unity的新手开发者来说&#xff0c;构建完整的游戏系统往往充满挑战。本文将手把手教你实现游戏开发中最常见的四大核心系统&#xff1a;主菜单界面、过场动画、成就系统和多语言支持。每个模块都将结合完整代码示例&#xff0c;使用Unity 2022 LTS版本进行演示…...

AI数字人:未来职业的重塑(9/10)

摘要&#xff1a;AI 数字人凭借计算机视觉、自然语言处理与深度学习技术&#xff0c;从虚拟形象进化为智能交互个体&#xff0c;广泛渗透金融、教育、电商等多领域&#xff0c;重构职业生态。其通过降本提效、场景拓展与体验升级机制&#xff0c;替代重复岗位工作&#xff0c;催…...

Android插拔U盘导致黑屏问题排查

问题现象&#xff1a; 车机大屏偶先插拔带音乐的U盘&#xff0c;导致车机系统短暂黑屏的情况。 日志中可以看到vold进程unmount了两次分区&#xff0c;一次是U盘分区&#xff0c;一次是/storage/emulated/0分区&#xff1a; I vold : Start killProcesses: /mnt/media_rw/…...

深入解析Mlivus Cloud中的etcd配置:最佳实践与高级调优指南

作为大禹智库的向量数据库高级研究员,我在《向量数据库指南》一书中详细阐述了向量数据库的核心组件及其优化策略。今天,我将基于30余年的实战经验,深入剖析Mlivus Cloud中etcd这一关键依赖的配置细节与优化方法。对于希望深入掌握Mlivus Cloud的读者,我强烈建议参考《向量…...

分享一个可以批量巡检GET和POST接口的Shell脚本

一、场景痛点与需求分析 在分布式系统架构中&#xff0c;服务接口的可用性和稳定性直接影响业务连续性。当面临以下场景时&#xff0c;需批量巡检GET和POST接口&#xff1a; 上线验证&#xff1a;新版本发布后批量验证核心接口 故障恢复&#xff1a;异常数据修复后的批量重试…...

前端面试宝典---vue原理

vue的Observer简化版 class Observer {constructor(value) {if (!value || typeof value ! object) returnthis.walk(value) // 对对象的所有属性进行遍历并定义响应式}walk (obj) {Object.keys(obj).forEach(key > defineReactive(obj, key, obj[key]))} } // 定义核心方法…...

PyTorch卷积层填充(Padding)与步幅(Stride)详解及代码示例

本文通过具体代码示例讲解PyTorch中卷积操作的填充&#xff08;Padding&#xff09;和步幅&#xff08;Stride&#xff09;对输出形状的影响&#xff0c;帮助读者掌握卷积层的参数配置技巧。 一、填充与步幅基础 填充&#xff08;Padding&#xff09;&#xff1a;在输入数据边缘…...

2025年Redis分片存储性能优化指南

一、分片规则与负载均衡 动态哈希分片‌ 采用CRC16算法计算键哈希值&#xff0c;通过hash_slot CRC16(key) % 16384确定槽位分布&#xff0c;结合Redis Cluster自动管理槽位迁移。 总分片数按需动态调整&#xff0c;例如从16节点扩容至32节点时&#xff0c;触发槽位重分配以…...

【概念】什么是 JWT Token?

—什么是 JWT Token&#xff1f; JWT Token&#xff08;JSON Web Token&#xff09; 就是一张后端发给前端的小票&#xff0c;里面包含用户身份信息&#xff0c;用于做无状态认证&#xff08;Stateless Authentication&#xff09;。 每次前端访问后端接口&#xff0c;都拿着…...

部署大模型需要多少GPU显存?以DeepSeek R1部署为例

引言 部署大型语言模型&#xff08;LLM&#xff09;时究竟需要多少GPU显存&#xff1f;本文将进行一次简单测算。 如何计算 算法1 可以用一个简单的公式来计算显存占用&#xff08;单位GB&#xff09;&#xff1a; 参数说明如下&#xff1a; 符号 含义 M 所需的 GPU 显存…...

用go从零构建写一个RPC(仿gRPC,tRPC)--- 版本1

希望借助手写这个go的中间件项目&#xff0c;能够理解go语言的特性以及用go写中间件的优势之处&#xff0c;同时也是为了更好的使用和优化公司用到的trpc&#xff0c;并且作者之前也使用过grpc并有一定的兴趣&#xff0c;所以打算从0构建一个rpc系统&#xff0c;对于生产环境已…...

Fedora 43 计划移除所有 GNOME X11 相关软件包

Fedora 43 计划移除所有 GNOME X11 相关软件包&#xff0c;这是 Fedora 项目团队为全面拥抱 Wayland 所做的重要决策。以下是关于此计划的详细介绍&#xff1a; 提案内容&#xff1a;4 月 23 日&#xff0c;Neal Gompa 提交提案&#xff0c;建议从 Fedora 软件仓库中移除所有 G…...

django之账号管理功能

账号管理功能 目录 1.账号管理页面 2.新增账号 3.修改账号 4.账号重置密码 5.删除账号功能 6.所有代码展示集合 7.运行结果 这一片文章, 我们需要新增账号管理功能, 今天我们写到的代码, 基本上都是用到以前所过的知识, 不过也有需要注意的细节。 一、账号管理界面 …...

搭建spark-local模式

要搭建Spark的local模式&#xff0c;你可以按照以下步骤进行操作&#xff08;以在Linux系统上安装为例&#xff0c;假设你已经安装了Java环境&#xff09;&#xff1a; 1. 下载Spark安装包&#xff1a;访问Spark官方网站&#xff08;https://spark.apache.org/downloads.html&a…...

月之暗面开源 Kimi-Audio-7B-Instruct,同时支持语音识别和语音生成

我们向您介绍在音频理解、生成和对话方面表现出色的开源音频基础模型–Kimi-Audio。该资源库托管了 Kimi-Audio-7B-Instruct 的模型检查点。 Kimi-Audio 被设计为通用的音频基础模型&#xff0c;能够在单一的统一框架内处理各种音频处理任务。主要功能包括&#xff1a; 通用功…...

IDEA配置将Servlet真正布署到Tomcat

刚开始只能IDEA运行完Servlet web application 并保持IDEA运行才能通过浏览器访问到我的Servlet&#xff0c;跟想象中的不一样&#xff0c;不应该是IDEA运行完项目以后只要打开Tomcat就能访问吗&#xff1f;事实时运行完项目只要关掉IDEA就不能再访问到应用了&#xff0c;而且T…...

删除新安装IBM Guardium Data Protection 12.1的baltimorecybertrustroot证书

登录web console&#xff0c;会显示 baltimorecybertrustroot证书过期警告。 采用下面的命令删除过期证书就可消除警告。 collector02.cpd.com> delete certificate keystore Select an alias from the list below to delete the corresponding certificate. Alias List:…...

【蓝桥杯】画展布置

画展布置 题目描述 画展策展人小蓝和助理小桥为即将举办的画展准备了 N N N 幅画作&#xff0c;其艺术价值分别为 A 1 , A 2 , … , A N A_1, A_2, \dots , A_N A1​,A2​,…,AN​。他们需要从这 N N N 幅画中挑选 M M M 幅&#xff0c;并按照一定顺序布置在展厅的 M M …...

请求参数、路径参数、查询参数、Spring MVC/FeignClient请求相关注解梳理

目录 1 请求分类1.1 URL参数--查询参数1.2 URL参数--路径参数 2 请求相关注解2.1 RequestParam--查询参数2.2 PathVariable--路径参数2.3 RequestBody2.4 Param & RequestLine2.5 SpringMVC请求参数注解用在FeignClient里 使用SpringMVC处理http请求或使用FeignClient进行请…...

MySQL 详解之复制与集群:构建高可用与可扩展数据库架构

随着业务的发展,单一的数据库实例往往难以满足需求: 性能瓶颈: 读写请求量不断增加,单个服务器的 CPU、内存、磁盘、网络资源达到上限,尤其是读请求远大于写请求的场景。高可用性: 单个服务器一旦发生故障(硬件故障、操作系统问题、机房断电等),数据库服务将完全中断,…...

刚体运动 (位置向量 - 旋转矩阵) 笔记 1.1~1.3 (台大机器人学-林沛群)

目录 1. 理解刚体的“自由度”&#xff08;Degrees of Freedom, DOF&#xff09; 1.1 平面运动 (2D) 1.2 空间运动 (3D) 2. 统一描述&#xff1a;引入“体坐标系”&#xff08;Body Frame&#xff09; 3. 从“状态”到“运动”&#xff1a;引入微分 3.1 补充&#xff1a;…...

openAICEO山姆奥特曼未来预测雄文之三个观察

《三个观察》 山姆奥特曼 这篇文章主要讲的是关于AGI&#xff08;人工通用智能&#xff09;的未来发展及其对社会的影响&#xff0c;用大白话总结如下&#xff1a; 核心观点&#xff1a; AGI是什么&#xff1f; AGI是一种能像人类一样解决各种复杂问题的智能系统&#xff0c;比…...