【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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/81055.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/81055.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/81055.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

pytest 技術總結

目錄 一 pytest的安裝&#xff1a; 二 pytest有三種啟動方式&#xff1a; 三 用例規則&#xff1a; 四 配置框架&#xff1a; 一 pytest的安裝&#xff1a; pip install pytest # 安裝 pip install pytest -U # 升級到最新版 二 pytest有三種啟動方式&#xff1a; 1…

redis 有序集合zrange和zrangebyscore的區別

起因是查詢數據&#xff0c;用了zrangebyscore 但是一直顯示沒數據 具體命令zrangebyscore key 0 -1 withscores, 原有印象中一直是這么用的&#xff0c;但是突然查不出來了&#xff0c; 于是搜了下問題所在。 通過分數查看 不能用0和-1表示最小和最大&#xff0c;只能用分數來…

Tableau 基礎表制作

目錄 1.數據連接 2. 數據可視化 3. 基礎表制作 3.1 對比分析&#xff1a;比大小 1. 柱狀圖 2. 條形圖 3. 熱力圖 4. 氣泡圖 5. 詞云 3.2 變化分析&#xff1a;看趨勢 1. 折線圖 2. 面積圖 3.3 構成分析&#xff1a;看占比 1. 餅圖 2. 樹地圖 3. 堆積圖 3.4 關…

反序列化漏洞1

一、PHP類與對象 1. 類 概念理解: 類是共享相同結構和行為的對象的集合&#xff0c;可以理解為特征的提取。例如將耳朵長、尾巴短、紅眼睛、吃胡蘿卜、蹦跳行走的動物特征抽象為"兔子"類。代碼結構: 使用class關鍵字定義類類名遵循大駝峰命名法包含成員變量(屬性)和…

為什么要對 ACI 網絡進行升級?

一、硬件演進 1. 交換機接口 前面板接口由 1/10G 升級至 10/25/100G fabric 上行鏈路 40G 升級至 100/400G 2. 交換機角色 交換機可以是 spine 或者 leaf,而不是固定角色 3. EOS APIC-SERVER-M2/L2 2024年6月30日 EOS,替換設備為 APIC-SERVER-M4/L4 二、網絡升級參考文…

DeepSeek+Cline:開啟自動化編程新紀元

目錄 一、引言&#xff1a;AI 編程時代的曙光二、認識 DeepSeek 和 Cline2.1 DeepSeek 是什么2.2 Cline 詳解2.3 兩者結合的魅力 三、DeepSeek Cline 安裝與配置全流程3.1 安裝 VS Code3.2 安裝 Cline 插件3.3 獲取 DeepSeek API Key3.4 配置 Cline 與 DeepSeek 連接 四、實戰演…

【展位預告】正也科技將攜營銷精細化管理解決方案出席中睿營銷論壇

在醫藥行業面臨政策深化、技術迭代、全球化競爭的多重挑戰下&#xff0c;第二屆中睿醫藥健康生態生長力峰會暨第三十五屆中睿醫藥營銷論壇將于廣州盛大啟幕。5月19-20日本次峰會以“聚焦政策變革、把握產業趨勢、構建生態共贏”為核心&#xff0c;旨在通過全產業鏈資源整合與創…

【深度學習】評估模型復雜度:GFLOPs與Params詳解

評估模型復雜度&#xff1a;GFLOPs與Params詳解 在深度學習模型設計與優化過程中&#xff0c;GFLOPs和Params是論文中兩個重要的評估指標&#xff0c;它們分別衡量模型的計算復雜度和參數量。本文將詳細介紹這兩個概念及其在實踐中的應用。 1. Params&#xff1a;模型參數量 …

Go語言->練習6例

1.go語言的接口實現 接口&#xff08;interface&#xff09;是一種類型&#xff0c;它定義了一組方法的集合。任何類型只要實現了接口中定義的所有方法&#xff0c;就被認為實現了該接口。 在Go語言中&#xff0c;使用接口的最佳實踐可以提高代碼的可讀性、可維護性和靈活性。…

Drivestduio 代碼筆記與理解

Rigid Node: 表示 car或者trucks Deformable Node : 表示一些 分布之外的 non-rigid 的運動物體&#xff0c; 比如遠處的行人等和Cyclist。 在 load_objects 會讀取每一個 dynamic objects 的 bounding box’的信息&#xff0c;具體如下&#xff1a; frame_instances 記錄了每…

《算法筆記》10.5小節——圖算法專題->最小生成樹 問題 E: Jungle Roads

題目描述 The Head Elder of the tropical island of Lagrishan has a problem. A burst of foreign aid money was spent on extra roads between villages some years ago. But the jungle overtakes roads relentlessly, so the large road network is too expensive to mai…

【音視頻】SDL簡介

官網&#xff1a;官網 文檔&#xff1a;文檔 SDL&#xff08;Simple DirectMedia Layer&#xff09;是一套開放源代碼的跨平臺多媒體開發庫&#xff0c;使用C語言寫成。SDL提供數種控制圖像、聲音、輸出入的函數&#xff0c;讓開發者只 要用相同或是相似的代碼就可以開發出跨多…

SpringBoot + SSE 實時異步流式推送

前言 在當今數字化時代&#xff0c;實時數據處理對于企業的決策和運營至關重要。許多業務場景需要及時響應數據庫中的數據變化&#xff0c;例如電商平臺實時更新庫存、金融系統實時監控交易數據等。 本文將詳細介紹如何通過Debezium捕獲數據庫變更事件&#xff0c;并利用Serv…

ADS1299模擬前端(AFE)代替芯片——LHE7909

在現代醫療科技的飛速發展中&#xff0c;精確的生物電勢測量設備變得越來越重要。領慧立芯推出的LHE7909&#xff0c;是一款專為心電圖&#xff08;ECG&#xff09;和其他生物電勢測量設計的低噪聲24位模數轉換器&#xff08;ADC&#xff09;&#xff0c;為醫療設備制造商提供了…

如何實現Redis和Mysql中數據雙寫一致性

一、引言 今天我們來聊聊一個在分布式系統中非常常見但又十分棘手的問題——Redis與MySQL之間的雙寫一致性。我們在項目中多多少少都遇到過類似的困擾&#xff0c;緩存是用Redis&#xff0c;數據庫是用MySQL&#xff0c;但如何確保兩者之間的數據一致性呢&#xff1f;接下來我…

面試篇 - Transformer前饋神經網絡(FFN)使用什么激活函數?

1. FFN結構分解 原始Transformer的FFN層 FFN(x) max(0, xW? b?)W? b? # 原始論文公式 輸入&#xff1a;自注意力層的輸出 x&#xff08;維度 d_model512&#xff09; 擴展層&#xff1a;xW? b?&#xff08;擴展為 d_ff2048&#xff09; 激活函數&#xff1a;Re…

基于Python Flask的深度學習電影評論情感分析可視化系統(2.0升級版,附源碼)

博主介紹&#xff1a;?IT徐師兄、7年大廠程序員經歷。全網粉絲15W、csdn博客專家、掘金/華為云//InfoQ等平臺優質作者、專注于Java技術領域和畢業項目實戰? &#x1f345;文末獲取源碼聯系&#x1f345; &#x1f447;&#x1f3fb; 精彩專欄推薦訂閱&#x1f447;&#x1f3…

前端vue2修改echarts字體為思源黑體-避免侵權-可以更換為任意字體統一管理

1.下載字體 npm install fontsource/noto-sans-sc 不知道為什么我從github上面下載的不好使&#xff0c;所以就用了npm的 2.引用字體 import fontsource/noto-sans-sc; 在入口文件-main.js中引用 3.設置echats模板樣式 import * as echarts from echarts; // 在import的后…

51c自動駕駛~合集37

我自己的原文哦~ https://blog.51cto.com/whaosoft/13878933 #DETR->DETR3D->Sparse4D 走向長時序稀疏3D目標檢測 一、DETR 圖1 DETR架構 DETR是第一篇將Transformer應用到目標檢測方向的算法。DETR是一個經典的Encoder-Decoder結構的算法&#xff0c;它的骨干網…

【MongoDB篇】MongoDB的集合操作!

目錄 引言第一節&#xff1a;集合的“誕生”——自動出現還是手動打造&#xff1f;&#x1f914;第二節&#xff1a;集合的“查閱”——看看這個數據庫里有哪些柜子&#xff1f;&#x1f4c2;&#x1f440;第三節&#xff1a;集合的“重命名”——給文件柜換個名字&#xff01;…