文章目录
- 1、Android服务
-
- 1.1、定义
- 1.2、基本用法
- 1.3、带绑定的服务示例
-
- 1.3.1、定义服务类
- 1.3.2、客户端(Activity)绑定与交互
- [1.3.3、AndroidManifest.xml 注册](#1.3.3、AndroidManifest.xml 注册)
- 1.3.4、关键点
- 2、Android通知
-
- [2.1、创建通知渠道(Android 8.0+ 必需)](#2.1、创建通知渠道(Android 8.0+ 必需))
- 2.2、发送基础通知
- 2.3、在Activity中调用
- 3、Android前台服务
-
- 3.1、创建前台服务类(MyForegroundService.java)
- [3.2、在 AndroidManifest.xml 中注册服务和权限](#3.2、在 AndroidManifest.xml 中注册服务和权限)
- [3.3、从 Activity 启动服务](#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()方法里
java
public class MyService extends Service {
private static final String TAG = "MyService";
private Handler handler;
private Runnable task;
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "服务创建");
// 初始化Handler和定时任务(示例:每秒打印日志)
handler = new Handler(Looper.getMainLooper());
task = new Runnable() {
@Override
public void run() {
Log.d(TAG, "服务运行中: " + System.currentTimeMillis());
handler.postDelayed(this, 1000); // 每隔1秒执行一次
}
};
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "服务启动");
handler.post(task); // 启动定时任务
return START_STICKY; // 服务被终止后自动重启
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "服务销毁");
handler.removeCallbacks(task); // 停止任务,避免内存泄漏
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
1.2.2、服务注册
- 每一个服务都需要在AndroidManifest.xml文件中进行注册才能生效
xml
<application>
<service android:name=".MyService" android:enabled="true" />
</application>
1.2.3、启动和停止服务
- 启动和停止的方法主要是借助Intent来实现的
- startService()和stopService()方法都是定义在Context类中的,所以我们在活动里可以直接调用这两个方法。
- onCreate()方法是在服务第一次创建的时候调用的,而onStartCommand()方法则在每次启动服务的时候都会调用。
- 服务应在工作完成后通过调用 stopSelf() 停止自身,或者另一个组件可以通过调用 stopService() 停止它。
java
//从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、定义服务类
java
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 对象
@Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "服务创建");
handler = new Handler(Looper.getMainLooper());
task = new Runnable() {
@Override
public void run() {
Log.d(TAG, "服务运行中: " + System.currentTimeMillis());
handler.postDelayed(this, 1000);
}
};
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "服务启动");
handler.post(task);
return START_STICKY;
}
// 2. 实现绑定功能
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "客户端绑定");
return mBinder; // 返回 Binder 对象
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "所有客户端解绑");
return super.onUnbind(intent);
}
@Override
public 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)绑定与交互
java
public class MainActivity extends AppCompatActivity {
private MyService myService;
private boolean isBound = false;
// 1. 定义 ServiceConnection
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
MyService.MyBinder binder = (MyService.MyBinder) service;
myService = binder.getService(); // 获取服务实例
isBound = true;
Log.d("Client", "绑定成功,计数器值: " + myService.getCounter());
}
@Override
public void onServiceDisconnected(ComponentName name) {
isBound = false;
}
};
@Override
protected 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();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
// 4. 解绑服务
if (isBound) {
unbindService(connection);
isBound = false;
}
}
}
1.3.3、AndroidManifest.xml 注册
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+ 必需)
java
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、发送基础通知
java
private void sendSimpleNotification(Context context) {
// 1. 获取NotificationManager
NotificationManager notificationManager =
(NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
// 2. 创建点击通知后跳转的Intent
Intent 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中调用
java
@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)
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;
@Override
public void onCreate() {
super.onCreate();
createNotificationChannel(); // 创建通知渠道(Android 8.0+必需)
}
@Override
public 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
@Override
public IBinder onBind(Intent intent) {
return null; // 不提供绑定功能
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, "服务已停止");
}
}
3.2、在 AndroidManifest.xml 中注册服务和权限
java
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<application>
<service
android:name=".MyForegroundService"
android:enabled="true"
android:exported="false" />
</application>
3.3、从 Activity 启动服务
java
// 启动前台服务(兼容 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、停止服务
java
// 停止服务
Intent stopIntent = new Intent(this, MyForegroundService.class);
stopService(stopIntent);
3.5、注意事项
- 通知渠道:Android 8.0 及以上版本必须创建通知渠道,否则通知无法显示。
- 5秒规则:调用 startForegroundService()后需在5秒内调用 startForeground(),否则会触发 ANR。
- 权限:Android 10+ 需在清单中声明 FOREGROUND_SERVICE权限。
- 线程管理:前台服务默认在主线程运行,耗时操作需另启线程(如示例中的 Thread)。