糗事百科网站源码/网络推广哪个平台效果最好
前言
服务(Service)是Android中实现程序后台运行的解决方案,非常适合用于执行那些不需要和用户交互且长期运行的任务。
要点
- 依赖于创建服务时所在的应用进程,不是运行在一个独立的进程当中。
- 耗时操作需要在服务内部手动创建子线程,并在这里执行具体任务,否则就有可能会出现主线程被阻塞住的情况。
生命周期
Service 有三种启动服务的方式:
- 启动服务:startService()开启服务,stopService()关闭服务
startService() 回调 onCreate ——> onStartCommand
stopService() 回调 onDestroy
- 绑定服务:bindService()绑定服务,unbindService()解绑服务。客户端通过一个IBinder接口与服务进行通信
bindService() 回调 onCreate ——> onBind
unbindService() 回调 onUnBind——>onDestory
- 混合方式: 先开启服务,再绑定服务
startService() 回调 onCreate ——> onStartCommand; bindService() 回调 onBind,unbindService() 回调 onUnBind; stopService() 回调 onDestroy
要点:
- 无论开启service多少次,onCreate 方法仅会调用一次,并且系统只会创建Service的一个实例
- 整个生命周期方法里,只有onStartCommand 方法可以多次调用,其他方法只能调用1次
- onStartCommand() 调用次数= startService() 调用次数
- 多个客户端可以绑定到同一个服务上,当所有的客户端都解除绑定后,系统会销毁服务
小结:
- startService开启服务,但无法操作服务
- bindService绑定服务,还能操作服务
Service分类
- 按运行地点分为:本地服务和远程服务
本地服务
用于应用程序内部,实现一些耗时任务,最普通、最常用的后台服务Service。
实例
MyService 类
public class MyService extends Service {@Overridepublic void onCreate() {super.onCreate();System.out.println("执行了onCreat()");}@Overridepublic int onStartCommand(Intent intent, int flags, int startId) {System.out.println("执行了onStartCommand()");return super.onStartCommand(intent, flags, startId);}@Overridepublic void onDestroy() {super.onDestroy();System.out.println("执行了onDestory()");}@Nullable@Overridepublic 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解绑服务
@Overridepublic 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() {@Overridepublic 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);}@Overridepublic void onServiceDisconnected(ComponentName componentName) {}};
在AndroidManifest.xml里注册Service
<service android:name=".MyService" />
运行结果为
远程服务
用于Android系统内部的应用程序之间,可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。可以定义接口并把接口暴露出来,以便其他应用进行操作。客户端建立到服务对象的连接,并通过那个连接来调用服务。
步骤
服务器端:
- 新建定义AIDL文件,并声明该服务需要向客户端提供的接口
- 在Service子类中实现AIDL中定义的接口方法,并定义生命周期的方法
- 在AndroidMainfest.xml中注册服务且声明为远程服务
服务器端实例
新建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() {}@Overridepublic IBinder onBind(Intent intent) {System.out.println("-------->onBind");return mBinder;}AIDLService.Stub mBinder = new AIDLService.Stub() {@Overridepublic void aidlService() throws RemoteException {System.out.println("客户端通过AIDL与远程后台成功通信");}};
}
在AndroidMainfest.xml中注册服务 & 声明为远程服务
<serviceandroid:name=".service.ServiceDemo"android:exported="true" //设置可被其他进程调用android:process=":remote">//将本地服务设置成远程服务<intent-filter>// 此处Intent的action必须写成“服务器端包名.aidl文件名”<action android:name="com.xf.AIDLService"/></intent-filter></service>
客户端:
- 拷贝服务端的AIDL文件到目录下
- 使用Stub.asInterface接口获取服务器的Binder,根据需要调用服务提供的接口方法
- 通过Intent指定服务端的服务名称和所在包,绑定远程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() {@Overridepublic void onServiceConnected(ComponentName componentName, IBinder iBinder) {//使用asInterface()方法获取服务器端返回的IBinder对象//将IBinder对象传换成了AIDLService接口对象mAidlService = AIDLService.Stub.asInterface(iBinder);try {mAidlService.aidlService();} catch (RemoteException e) {e.printStackTrace();}}@Overridepublic void onServiceDisconnected(ComponentName componentName) {}};
测试结果:
从上面测试结果可以看出,客户端调用了服务端Service的方法,即客户端和服务端进行了跨进程通信。
本地服务与远程服务比较
- 按运行类型分为前台服务和后台服务
前台服务
前台服务是指那些经常会被用户关注的服务,因此内存过低时它不会成为被杀的对象。 前台服务必须提供一个状态栏通知,并会置于“正在进行的”(“Ongoing”)组之下。这意味着只有在服务被终止或从前台移除之后,此通知才能被解除。
实例
在Service类的onCreate方法开启前台服务
@Overridepublic 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()方法,这个方法接受个布尔参数,表示是否同时移除状态栏通知
测试结果
前台服务与后台服务比较
Service相关知识
- bindService() 在进行服务绑定的时,其flags有:
- Context.BIND_AUTO_CREATE
表示收到绑定请求的时候,如果服务尚未创建,则即刻创建; 在系统内存不足需要先摧毁优先级组件来释放内存,且只有驻留该服务的进程成为被摧毁对象时,服务才被摧。 - Context.BIND_DEBUG_UNBIND
通常用于调试场景中判断绑定的服务是否正确,但容易引起内存泄漏,因此非调试目的的时候不建议使用 - Context.BIND_NOT_FOREGROUND
表示系统将阻止驻留该服务的进程具有前台优先级,仅在后台运行
- Service 元素的属性:
- android:name :服务类名
- android:label :服务的名字,如果此项不设置,那么默认显示的服务名则为类名
- android:icon:服务的图标
- android:permission:申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务
- android:process:表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字
- android:enabled :如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false
- android:exported:表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false
- onStartCommand()方法必须返回一个整数。这个整数是描述系统在杀死服务之后应该如何继续运行
- START_STICKY
如果系统在onStartCommand()返回后杀死了服务,则将重建服务并调用onStartCommand(),但不会再次送入上一个intent, 而是用null intent来调用onStartCommand() 。除非还有启动服务的intent未发送完,那么这些剩下的intent会继续发送。 这适用于媒体播放器(或类似服务),它们不执行命令,但需要一直运行并随时待命。
- START_NOT_STICKY
如果系统在onStartCommand()返回后杀死了服务,则不会重建服务了,除非还存在未发送的intent。 当服务不再是必需的,并且应用程序能够简单地重启那些未完成的工作时,这是避免服务运行的最安全的选项。
- START_REDELIVER_INTENT
如果系统在onStartCommand()返回后杀死了服务,则将重建服务并用上一个已送过的intent调用onStartCommand()。任何未发送完的intent也都会依次送入。这适用于那些需要立即恢复工作的活跃服务,比如下载文件。