文章目錄
- 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提供的方法了。
示例說明:
- 在服務類中定義Binder的內部類,此內部類定義獲取服務實例的函數,以供活動中調用;
- 在活動中定義ServiceConnection匿名類在重寫的方法中服務的實例;
- 獲取到服務實例后,就可以調用服務定義的方法。
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)。