服务(Service)是Android中实现程序后台运行的解决方案,非常适合用于执行那些不需要和用户交互且长期运行的任务。
startService() 回调 onCreate ——> onStartCommand
stopService() 回调 onDestroy
bindService() 回调 onCreate ——> onBind
unbindService() 回调 onUnBind——>onDestory
startService() 回调 onCreate ——> onStartCommand; bindService() 回调 onBind,unbindService() 回调 onUnBind; stopService() 回调 onDestroy
要点:
小结:
用于应用程序内部,实现一些耗时任务,最普通、最常用的后台服务Service。
MyService 类
public class MyService extends Service {
@Override
public void onCreate() {
super.onCreate();
System.out.println("执行了onCreat()");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
System.out.println("执行了onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
System.out.println("执行了onDestory()");
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
private MyBinder mBinder = new MyBinder();
class MyBinder extends Binder {
public String printServiceInfo() {
return "Activity 和 Service 建立通信,传递数据";
}
}
}
在Activity 里构建Intent对象,并调用startService()启动Service、stopService停止服务,bindService绑定服务、unbindService解绑服务
@Override
public void onClick(View view) {
Intent i = new Intent(MainActivity.this, MyService.class);
switch (view.getId()) {
case R.id.btn_start_service:
startService(i);
break;
case R.id.btn_stop_service:
stopService(i);
break;
case R.id.btn_bind_service:
bindService(i, connection, BIND_AUTO_CREATE);
break;
case R.id.btn_unbind_service:
unbindService(connection);
break;
}
}
private MyService.MyBinder myBinder;
//创建ServiceConnection的匿名类
private ServiceConnection connection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//实例化Service的内部类myBinder
//通过向下转型得到了MyBinder的实例,Binder实现了IBinder 接口
myBinder = (MyService.MyBinder) iBinder;
//在Activity调用Service类的方法
String info = myBinder.printServiceInfo();
System.out.println("---------->" + info);
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
在AndroidManifest.xml里注册Service
<service android:name=".MyService" />
用于Android系统内部的应用程序之间,可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。可以定义接口并把接口暴露出来,以便其他应用进行操作。客户端建立到服务对象的连接,并通过那个连接来调用服务。
服务器端:
新建AIDL文件,在新建AIDL文件里定义Service需要与Activity进行通信的内容(方法),并进行编译(Make Project)
interface AIDLService {
/**
* //AIDL中支持以下的数据类型
//1. 基本数据类型
//2. String 和CharSequence
//3. List 和 Map ,List和Map 对象的元素必须是AIDL支持的数据类型;
//4. AIDL自动生成的接口(需要导入-import)
//5. 实现android.os.Parcelable 接口的类(需要导入-import)
*/
void aidlService();
}
在Service子类中实现AIDL中定义的接口方法,并定义生命周期的方法
public class ServiceDemo extends Service {
public ServiceDemo() {
}
@Override
public IBinder onBind(Intent intent) {
System.out.println("-------->onBind");
return mBinder;
}
AIDLService.Stub mBinder = new AIDLService.Stub() {
@Override
public void aidlService() throws RemoteException {
System.out.println("客户端通过AIDL与远程后台成功通信");
}
};
}
在AndroidMainfest.xml中注册服务 & 声明为远程服务
<service
android:name=".service.ServiceDemo"
android:exported="true" //设置可被其他进程调用
android:process=":remote">//将本地服务设置成远程服务
<intent-filter>
// 此处Intent的action必须写成“服务器端包名.aidl文件名”
<action android:name="com.xf.AIDLService"/>
</intent-filter>
</service>
客户端:
将服务端的AIDL文件所在的包复制到客户端目录下(Project/app/src/main),并进行编译
在Activity里,使用Stub.asInterface接口获取服务器的Binder;通过Intent指定服务端的服务名称和所在包,进行Service绑定;根据需要调用服务提供的接口方法。
// 开启服务
case R.id.btn_remote_service:
Intent intent = new Intent("com.xf.AIDLService");
intent.setPackage("com.xf");
bindService(intent, reConn, BIND_AUTO_CREATE);
break;
// 连接 远程服务
private AIDLService mAidlService;
private ServiceConnection reConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
//使用asInterface()方法获取服务器端返回的IBinder对象
//将IBinder对象传换成了AIDLService接口对象
mAidlService = AIDLService.Stub.asInterface(iBinder);
try {
mAidlService.aidlService();
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName componentName) {
}
};
测试结果:
从上面测试结果可以看出,客户端调用了服务端Service的方法,即客户端和服务端进行了跨进程通信。
前台服务是指那些经常会被用户关注的服务,因此内存过低时它不会成为被杀的对象。 前台服务必须提供一个状态栏通知,并会置于“正在进行的”(“Ongoing”)组之下。这意味着只有在服务被终止或从前台移除之后,此通知才能被解除。
在Service类的onCreate方法开启前台服务
@Override
public void onCreate() {
super.onCreate();
System.out.println("------->onCreate");
// 前台服务
String channelID = "com.xf.serviceclientdemo";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
NotificationChannel channel = new NotificationChannel(channelID, "前台服务", NotificationManager.IMPORTANCE_HIGH);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
}
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, channelID)
.setContentTitle("前台服务通知的标题")
.setContentText("前台服务通知的内容")
.setSmallIcon(R.mipmap.ic_launcher)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);//让Service变成前台Service,并在系统的状态栏显示出来
}
要从前台移除服务,请调用stopForeground()方法,这个方法接受个布尔参数,表示是否同时移除状态栏通知
如果系统在onStartCommand()返回后杀死了服务,则将重建服务并调用onStartCommand(),但不会再次送入上一个intent, 而是用null intent来调用onStartCommand() 。除非还有启动服务的intent未发送完,那么这些剩下的intent会继续发送。 这适用于媒体播放器(或类似服务),它们不执行命令,但需要一直运行并随时待命。
如果系统在onStartCommand()返回后杀死了服务,则不会重建服务了,除非还存在未发送的intent。 当服务不再是必需的,并且应用程序能够简单地重启那些未完成的工作时,这是避免服务运行的最安全的选项。
如果系统在onStartCommand()返回后杀死了服务,则将重建服务并用上一个已送过的intent调用onStartCommand()。任何未发送完的intent也都会依次送入。这适用于那些需要立即恢复工作的活跃服务,比如下载文件。