Android—服務+通知=>前臺服務

文章目錄

  • 1、Android服務
    • 1.1、定義
    • 1.2、基本用法
      • 1.2.1、定義一個服務
      • 1.2.2、服務注冊
      • 1.2.3、啟動和停止服務
      • 1.2.4、活動和服務進行通信
    • 1.3、帶綁定的服務示例
      • 1.3.1、定義服務類
      • 1.3.2、客戶端(Activity)綁定與交互?
      • 1.3.3、AndroidManifest.xml 注冊?
      • 1.3.4、關鍵點
  • 2、Android通知
    • 2.1、創建通知渠道(Android 8.0+ 必需)?
    • 2.2、發送基礎通知?
    • 2.3、在Activity中調用
  • 3、Android前臺服務
    • 3.1、創建前臺服務類(MyForegroundService.java)?
    • 3.2、在 AndroidManifest.xml 中注冊服務和權限?
    • 3.3、從 Activity 啟動服務?
    • 3.4、停止服務
    • 3.5、注意事項??

1、Android服務

1.1、定義

  • 服務(Service)是Android中實現程序后臺運行的解決方案,它非常適合去執行那些不需要和用戶交互而且還要求長期運行的任務
  • 服務并不是運行在一個獨立的進程當中的,而是依賴于創建服務時所在的應用程序進程。當某個應用程序進程被殺掉時,所有依賴于該進程的服務也會停止運行。
  • 服務并不會自動開啟線程,所有的代碼都是默認運行在主線程當中的。 耗時操作需另啟線程(如HandlerThread或AsyncTask)

1.2、基本用法

1.2.1、定義一個服務

  • 要創建服務,您必須創建 Service 的子類或使用其現有子類之一
  • onBind()方法。這個方法是Service中唯一的一個抽象方法,所以必須要在子類里實現。
  • onCreate()方法會在服務創建的時候調用,onStartCommand()方法會在每次服務啟動的時候調用,onDestroy()方法會在服務銷毀的時候調用。
  • 如果希望服務一旦啟動就立刻去執行某個動作,就可以將邏輯寫在onStartCommand()方法里
public class MyService extends Service {private static final String TAG = "MyService";private Handler handler;private Runnable task;@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, "服務創建");// 初始化Handler和定時任務(示例:每秒打印日志)handler = new Handler(Looper.getMainLooper());task = new Runnable() {@Overridepublic void run() {Log.d(TAG, "服務運行中: " + System.currentTimeMillis());handler.postDelayed(this, 1000); // 每隔1秒執行一次}};}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "服務啟動");handler.post(task); // 啟動定時任務return START_STICKY; // 服務被終止后自動重啟}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG, "服務銷毀");handler.removeCallbacks(task); // 停止任務,避免內存泄漏}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null; }
}

1.2.2、服務注冊

  • 每一個服務都需要在AndroidManifest.xml文件中進行注冊才能生效
<application><service android:name=".MyService" android:enabled="true" />
</application>

1.2.3、啟動和停止服務

  • 啟動和停止的方法主要是借助Intent來實現的
  • startService()和stopService()方法都是定義在Context類中的,所以我們在活動里可以直接調用這兩個方法。
  • onCreate()方法是在服務第一次創建的時候調用的,而onStartCommand()方法則在每次啟動服務的時候都會調用。
  • 服務應在工作完成后通過調用 stopSelf() 停止自身,或者另一個組件可以通過調用 stopService() 停止它。
//從Activity啟動/停止服務?
// 啟動服務
Intent startIntent = new Intent(this, MyService.class);
startService(startIntent);// 停止服務
Intent stopIntent = new Intent(this, MyService.class);
stopService(stopIntent);

1.2.4、活動和服務進行通信

  • 應用組件(例如 activity)可以通過調用 startService() 并傳入指定服務并包含服務要使用的任何數據的 Intent 來啟動服務。服務會在 onStartCommand() 方法中接收此 Intent。
  • 當一個活動和服務綁定了之后,就可以調用該服務里的Binder提供的方法了

1.3、帶綁定的服務示例

  • 用于活動和服務進行通信,比如在活動中指揮服務去看什么,服務就去干什么,主要用onBind()方法
  • 當一個活動和服務綁定之后,就可以調用該服務里的Binder提供的方法了。

示例說明:

  1. 在服務類中定義Binder的內部類,此內部類定義獲取服務實例的函數,以供活動中調用;
  2. 在活動中定義ServiceConnection匿名類在重寫的方法中服務的實例;
  3. 獲取到服務實例后,就可以調用服務定義的方法。

1.3.1、定義服務類

public class MyService extends Service {private static final String TAG = "MyService";private Handler handler;private Runnable task;private int counter = 0; // 示例:用于客戶端交互的計數器// 1. 定義 Binder 類public class MyBinder extends Binder {public MyService getService() {return MyService.this; // 返回當前服務實例}}private final IBinder mBinder = new MyBinder(); // Binder 對象@Overridepublic void onCreate() {super.onCreate();Log.d(TAG, "服務創建");handler = new Handler(Looper.getMainLooper());task = new Runnable() {@Overridepublic void run() {Log.d(TAG, "服務運行中: " + System.currentTimeMillis());handler.postDelayed(this, 1000);}};}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {Log.d(TAG, "服務啟動");handler.post(task);return START_STICKY;}// 2. 實現綁定功能@Overridepublic IBinder onBind(Intent intent) {Log.d(TAG, "客戶端綁定");return mBinder; // 返回 Binder 對象}@Overridepublic boolean onUnbind(Intent intent) {Log.d(TAG, "所有客戶端解綁");return super.onUnbind(intent);}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG, "服務銷毀");handler.removeCallbacks(task);}// 3. 定義客戶端可調用的方法public int getCounter() {return counter++;}public String formatMessage(String input) {return "服務處理: " + input.toUpperCase();}
}

1.3.2、客戶端(Activity)綁定與交互?

public class MainActivity extends AppCompatActivity {private MyService myService;private boolean isBound = false;// 1. 定義 ServiceConnectionprivate ServiceConnection connection = new ServiceConnection() {@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {MyService.MyBinder binder = (MyService.MyBinder) service;myService = binder.getService(); // 獲取服務實例isBound = true;Log.d("Client", "綁定成功,計數器值: " + myService.getCounter());}@Overridepublic void onServiceDisconnected(ComponentName name) {isBound = false;}};@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 2. 綁定服務Intent intent = new Intent(this, MyService.class);bindService(intent, connection, Context.BIND_AUTO_CREATE);}// 3. 調用服務方法(示例:按鈕點擊事件)public void onButtonClick(View view) {if (isBound) {String result = myService.formatMessage("hello");Toast.makeText(this, result + " 計數:" + myService.getCounter(), Toast.LENGTH_SHORT).show();}}@Overrideprotected void onDestroy() {super.onDestroy();// 4. 解綁服務if (isBound) {unbindService(connection);isBound = false;}}
}

1.3.3、AndroidManifest.xml 注冊?

<service android:name=".MyService" android:enabled="true" />

1.3.4、關鍵點

  • ??Binder 機制??

    • 通過繼承 Binder類實現內部類,提供 getService()方法返回服務實例。
    • 客戶端通過 ServiceConnection獲取 IBinder對象并轉換為具體類型。
  • ??生命周期管理??

    • 綁定觸發順序:onCreate()→ onBind();解綁觸發 onUnbind()→ onDestroy()(若無其他綁定)。
    • 必須調用 unbindService()避免內存泄漏(通常在 onDestroy()中處理)。
  • ??線程安全??

    • 服務方法默認在主線程執行,若需耗時操作應另啟線程(如 HandlerThread)

2、Android通知

2.1、創建通知渠道(Android 8.0+ 必需)?

private void createNotificationChannel() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {String channelId = "my_channel_id";CharSequence name = "My Channel";String description = "Default Notification Channel";int importance = NotificationManager.IMPORTANCE_DEFAULT;NotificationChannel channel = new NotificationChannel(channelId, name, importance);channel.setDescription(description);NotificationManager notificationManager = getSystemService(NotificationManager.class);notificationManager.createNotificationChannel(channel);}
}

2.2、發送基礎通知?

private void sendSimpleNotification(Context context) {// 1. 獲取NotificationManagerNotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);// 2. 創建點擊通知后跳轉的IntentIntent intent = new Intent(context, TargetActivity.class);intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);// 3. 構建通知NotificationCompat.Builder builder = new NotificationCompat.Builder(context, "my_channel_id").setSmallIcon(R.drawable.ic_notification) // 必需的小圖標.setContentTitle("新消息提醒")              // 通知標題.setContentText("這是一條簡單的通知示例")   // 通知內容.setPriority(NotificationCompat.PRIORITY_DEFAULT) // 優先級.setContentIntent(pendingIntent)         // 設置點擊行為.setAutoCancel(true);                    // 點擊后自動消失// 4. 發送通知(ID唯一,可用于更新或取消)notificationManager.notify(1, builder.build());
}

2.3、在Activity中調用

@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);createNotificationChannel(); // 初始化通知渠道findViewById(R.id.btn_send).setOnClickListener(v -> {sendSimpleNotification(this); // 點擊按鈕發送通知});
}

3、Android前臺服務

  • ?Android 8.0+限制??:后臺服務需使用startForeground()并顯示通知,否則會被系統回收

3.1、創建前臺服務類(MyForegroundService.java)?

public class MyForegroundService extends Service {private static final String TAG = "MyForegroundService";private static final String CHANNEL_ID = "foreground_service_channel";private static final int NOTIFICATION_ID = 1;@Overridepublic void onCreate() {super.onCreate();createNotificationChannel(); // 創建通知渠道(Android 8.0+必需)}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {// 構建通知Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID).setContentTitle("前臺服務運行中").setContentText("正在執行后臺任務...").setSmallIcon(R.drawable.ic_notification) // 必需的小圖標.setPriority(NotificationCompat.PRIORITY_DEFAULT).build();// 將服務提升為前臺服務startForeground(NOTIFICATION_ID, notification);Log.d(TAG, "前臺服務已啟動");// 模擬任務(實際可替換為下載、播放等邏輯)new Thread(() -> {while (true) {try {Thread.sleep(1000);Log.d(TAG, "任務執行中...");} catch (InterruptedException e) {e.printStackTrace();}}}).start();return START_STICKY; // 服務被終止后自動重啟}// 創建通知渠道(Android 8.0+)private void createNotificationChannel() {if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {NotificationChannel channel = new NotificationChannel(CHANNEL_ID,"前臺服務通知",NotificationManager.IMPORTANCE_DEFAULT);NotificationManager manager = getSystemService(NotificationManager.class);manager.createNotificationChannel(channel);}}@Nullable@Overridepublic IBinder onBind(Intent intent) {return null; // 不提供綁定功能}@Overridepublic void onDestroy() {super.onDestroy();Log.d(TAG, "服務已停止");}
}

3.2、在 AndroidManifest.xml 中注冊服務和權限?

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" /><application><serviceandroid:name=".MyForegroundService"android:enabled="true"android:exported="false" />
</application>

3.3、從 Activity 啟動服務?

// 啟動前臺服務(兼容 Android 8.0+)
Intent serviceIntent = new Intent(this, MyForegroundService.class);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {startForegroundService(serviceIntent); // Android 8.0+ 專用方法
} else {startService(serviceIntent);
}

3.4、停止服務

// 停止服務
Intent stopIntent = new Intent(this, MyForegroundService.class);
stopService(stopIntent);

3.5、注意事項??

  • 通知渠道??:Android 8.0 及以上版本必須創建通知渠道,否則通知無法顯示。
  • ??5秒規則??:調用 startForegroundService()后需在5秒內調用 startForeground(),否則會觸發 ANR。
  • ??權限??:Android 10+ 需在清單中聲明 FOREGROUND_SERVICE權限。
  • 線程管理??:前臺服務默認在主線程運行,耗時操作需另啟線程(如示例中的 Thread)。

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

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

相關文章

從基礎功能到自主決策, Agent 開發進階路怎么走

Agent 開發進階路線大綱基礎功能實現核心模塊構建環境感知&#xff1a;傳感器數據處理&#xff08;視覺、語音、文本等輸入&#xff09;基礎動作控制&#xff1a;API調用、硬件驅動、簡單反饋機制狀態管理&#xff1a;有限狀態機&#xff08;FSM&#xff09;或行為樹&#xff0…

《動手學深度學習》讀書筆記—9.6編碼器-解碼器架構

本文記錄了自己在閱讀《動手學深度學習》時的一些思考&#xff0c;僅用來作為作者本人的學習筆記&#xff0c;不存在商業用途。 正如我們在9.5機器翻譯中所討論的&#xff0c;機器翻譯是序列轉換模型的一個核心問題&#xff0c;其輸入和輸出都是長度可變的序列。為了處理這種類…

DocBench:面向大模型文檔閱讀系統的評估基準與數據集分析

本文由「大千AI助手」原創發布&#xff0c;專注用真話講AI&#xff0c;回歸技術本質。拒絕神話或妖魔化。搜索「大千AI助手」關注我&#xff0c;一起撕掉過度包裝&#xff0c;學習真實的AI技術&#xff01; 一、數據集概述與核心目標 DocBench 是由研究團隊于2024年提出的首個…

Python高級排序技術:非原生可比對象的自定義排序策略詳解

引言&#xff1a;超越原生比較操作的排序挑戰在Python數據處理中&#xff0c;我們經常需要處理不原生支持比較操作的對象。根據2024年《Python開發者生態系統報告》&#xff0c;在大型項目中&#xff0c;開發者平均需處理28%的自定義對象排序需求&#xff0c;這些對象包括&…

低代碼系統的技術深度:超越“可視化操作”的架構與實現挑戰

在很多非開發者眼中&#xff0c;低代碼平臺似乎只是簡化流程、快速搭建頁面的工具。然而&#xff0c;在真實的企業級應用中&#xff0c;低代碼系統必須面對高并發請求、復雜業務規則、多角色權限、跨系統集成與持續演進等一系列工程挑戰。高效交付&#xff08;Rapid Delivery&a…

【NLP輿情分析】基于python微博輿情分析可視化系統(flask+pandas+echarts) 視頻教程 - 詞云圖-微博評論詞云圖實現

大家好&#xff0c;我是java1234_小鋒老師&#xff0c;最近寫了一套【NLP輿情分析】基于python微博輿情分析可視化系統(flaskpandasecharts)視頻教程&#xff0c;持續更新中&#xff0c;計劃月底更新完&#xff0c;感謝支持。今天講解詞云圖-微博評論詞云圖實現 視頻在線地址&…

Webpack核心技能:Webpack安裝配置與模塊化

一、webpack 的安裝和使用1. webpack 簡介webpack 是基于模塊化的打包 (構建)工具&#xff0c;它把一切視為模塊&#xff08;包括 JS、CSS、圖片等資源文件&#xff09;。工作原理&#xff1a;以開發時態的入口模塊為起點遞歸分析所有依賴關系經過壓縮、合并等處理最終生成運行…

數據結構---二級指針(應用場景)、內核鏈表、棧(系統棧、實現方式)、隊列(實現方式、應用)

一、二級指針的應用場景1、在被調函數中&#xff0c;想要修改主調函數中的指針變量&#xff0c;需要傳遞該指針變量的地址&#xff0c;形參用二級指針接收。2、指針數組的數組名是一個二級指針&#xff0c;指針數組的數組名作為參數傳遞時&#xff0c;可用二級指針接收。指針數…

NodeJs學習日志(1):windows安裝使用node.js 安裝express,suquelize,sqlite,nodemon

windows安裝使用node.js 安裝express&#xff0c;suquelize&#xff0c;sqlite 系統是win10&#xff0c;默認已經安裝好nodejs與npm包名作用expressWeb應用框架suquelize數據庫ORMsqlite數據庫nodemon代碼熱重載安裝express 添加express生成器 npm add express-generator4安裝e…

Cervantes:面向滲透測試人員和紅隊的開源協作平臺

Cervantes 是一個專為滲透測試人員和紅隊打造的開源協作平臺。它提供了一個集中式工作區&#xff0c;用于集中管理項目、客戶端、漏洞和報告。通過簡化數據組織和團隊協調&#xff0c;它有助于減少規劃和執行滲透測試所需的時間和復雜性。 作為 OWASP 旗下的開源解決方案&…

[Python 基礎課程]猜數字游戲

使用 Python 實現一個猜數字游戲&#xff0c;先隨機生成一個 1 到 100 之間的一個隨機整數&#xff0c;讓用戶猜測這個數是什么&#xff0c;每次都提示用戶猜大了還是猜小了&#xff0c;如果用戶猜對了&#xff0c;提示用戶猜對了&#xff0c;用了多少次&#xff0c;并且之前每…

文件加密實現

一、不依賴外部庫實現 使用自定義的XOR加密算法結合簡單的密鑰擴展。 實現說明 這個方案不依賴任何外部庫&#xff0c;僅使用C標準庫實現&#xff1a; 加密原理&#xff1a;采用XOR加密算法&#xff0c;這是一種簡單但有效的對稱加密方式&#xff0c;相同的密鑰可以用于加密和解…

Unity輕量觀察相機

一、腳本功能簡介ObserveCamera 是一個可直接掛載到任意 GameObject 上的通用攝像機控制腳本&#xff0c;支持以下功能&#xff1a;鼠標右鍵控制攝像機繞自身旋轉&#xff08;俯仰、水平&#xff09;鼠標左鍵拖拽目標對象進行平移&#xff08;局部 XY 平面移動&#xff09;鼠標…

1深度學習Pytorch-pytorch、tensor的創建、屬性、設備和類型轉換、數據轉換、常見操作(獲取元素、元素運算、形狀改變、相乘、廣播)

文章目錄PyTorchTensor1 Tensor 的創建1.torch.tensor2.torch.Tensor3. 線性張量4. 隨機張量5. 特定數值的張量2 Tensor 常見屬性1 屬性2 設備切換3 類型轉換torch.Tensor.to(dtype)類型專用方法創建張量時直接指定類型與 NumPy 數組的類型互轉4 數據轉換&#xff08;淺拷貝與深…

五、Istio管理網格外部服務

因語雀與csdn markdown 格式有區別&#xff0c;請查看原文&#xff1a; https://www.yuque.com/dycloud/pss8ys 一、Egress Listener 流量策略 前面學習了 sidecar 自動注入原理、inbound Listener、outbound Listener 等概念&#xff0c;也知道了 EgressListener 的流量策略…

Ubuntu20.04 離線安裝 FFmpeg 靜態編譯包

系統版本 Ubuntu20.04 去現場部署項目&#xff0c;發現現場的設備連接的內網&#xff0c;無法使用apt直接安裝ffmpeg &#xff0c;想解決也簡單&#xff0c;數據線連接手機使用共享網絡&#xff0c;再使用命令sudo apt install ffmpeg安裝即可&#xff0c;奈何現場百多臺設備&a…

C語言高級編程技巧與最佳實踐

C語言高級編程技巧與最佳實踐 - 完整版 目錄 宏定義與預處理技巧內存管理高級技巧函數指針與回調機制數據結構設計并發與多線程錯誤處理與異常機制性能優化技巧調試與測試技巧跨平臺編程安全編程實踐綜合演示示例 宏定義與預處理技巧 1. 條件編譯與平臺檢測 /*** 平臺和編譯…

cygwin+php教程(swoole擴展+redis擴展)

cygwin 1.下載cygwin安裝程序 &#xff1a;在Windows上獲得Linux的感覺 ? 2. 打開安裝包&#xff1a;setup-x86_64.exe 3.選擇安裝類型 從互聯網安裝首次安裝下載而不安裝僅下載軟件包不安裝從本地目錄安裝遷移程序時使用 4.選擇安裝目錄 5.選擇本地軟件包目錄&#xff…

Ethereum: Uniswap V3核心”Tick”如何引爆DEX的流動性革命?

大家好&#xff0c;今天&#xff0c;我們來聊聊一個在去中心化交易所&#xff08;DEX&#xff09;領域&#xff0c;尤其是自Uniswap V3問世以來&#xff0c;變得至關重要的概念——Tick&#xff08;流動性邊界&#xff09;。 如果大家接觸過DeFi&#xff0c;可能聽說過Uniswap …

【概念學習】什么是深度學習

人工智能 人工智能的簡潔定義如下&#xff1a;努力將通常由人類完成的智力任務自動化。 因此&#xff0c;人工智能是一個綜合性的領域&#xff0c;不僅包括機器學習與深度學習&#xff0c;還包括更多不涉及學習的方法。 在相當長的時間內&#xff0c;許多專家相信&#xff0c;只…