Service概述
Service作为Android四大组件中的一员,有着非常重要的地位。它没有交互界面,一般用于长期运行在后台来处理一些比较耗时的操作和为其他应用提供服务接口,如消息推送、音乐播放、定位服务、后台数据同步、长连接(如:蓝牙、IM)的数据收发及连接状态变化等。Service分为本地服务和远程服务,本地服务运行在主进程的主线程中,而远程服务则运行在独立进程的主线程中。当然如果在服务里面写了非常耗时的代码时可能会出现ANR的情况,这时你可以在Service在创建一个子线程来处理耗时逻辑。
Service的几个属性
android:enabled 表示该服务是否能后被系统实例化(激活),默认为true;
android:name 表示该服务的名字(完整类名或.xxx.XXService),不可缺少;
android:icon 表示该服务的图标,默认与<application>元素的icon属性值一致;
android:label 表示该服务的名字(可以在手机里面的应用管理里面看到);
android:permission 表示启动或绑定该服务所需的权限,如:android:permission="com.permission.xxx.service",则其他应用要想访问该服务,必须声明权限<uses-permission android:name="com.permission.xxx.service" />;
android:exported 表示能够被外包应用访问,它的默认值依赖与该服务所包含的过滤器,若至少包含了一个过滤器,则意味着该服务可以给外部的其他应用提供服务,因此默认值是true; 否则默认值为false,此时只能在应用程序的内部使用该服务或者具有相同用户ID 的应用程序的组件才能使用该服务;
android:process=":remote",代表在应用程序里需要该service时会自动创建新的进程。而如果是android:process="remote",没有“:”分号的则创建全局进程,不同的应用程序共享该进程。
Service的启动两种启动方式
第一种:startService(intent)
E/FirstService.java(10403): [onStartCommand:30]intent = Intent { cmp=com.leo.myservice/.FirstService (has extras) } ,flags = 0 ,startId = 1
E/FirstService.java(10492): [onCreate:23]服务被激活
E/FirstService.java(10492): [onStartCommand:30]intent = null ,flags = 0 ,startId = 2
E/FirstService.java(12336): [onStartCommand:30]intent = Intent { cmp=com.leo.myservice/.FirstService (has extras) } ,flags = 0 ,startId = 1
E/FirstService.java(12405): [onCreate:23]服务被激活
E/FirstService.java(12405): [onStartCommand:30]intent = Intent { cmp=com.leo.myservice/.FirstService (has extras) } ,flags = 1 ,startId = 1
第二种:bindService(Intent service, ServiceConnection conn, int flags)
E/FirstService.java(17091): [onBind:17]绑定服务被执行
E/MainActivity.java(17091): [onServiceConnected:68]连接成功
E/FirstService.java(19794): [onDestroy:39]服务被销毁
Activity与Service交互
public class FirstService extends Service { private FirstBinder mBinder = new FirstBinder(); @Override public IBinder onBind(Intent intent) { DebugLog.e("绑定服务被执行"); return mBinder; } @Override public void onCreate() { super.onCreate(); DebugLog.e("服务被激活"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { DebugLog.e("intent = " + intent + " ,flags = " + flags + " ,startId = " + startId); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { super.onDestroy(); DebugLog.e("服务被销毁"); } @Override public boolean onUnbind(Intent intent) { DebugLog.e("解绑服务被执行"); return super.onUnbind(intent); } @Override public void onRebind(Intent intent) { super.onRebind(intent); DebugLog.e("重新绑定被执行"); } public void info() { DebugLog.e("FirstService中的info方法被调用"); } class FirstBinder extends Binder { @Override public String getInterfaceDescriptor() { return "接口描述"; } FirstService getService() { return FirstService.this; } public void info() { DebugLog.e("FirstBinder中的info方法被调用"); } }}
public class MainActivity extends Activity { private FirstService mService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定FirstService Intent intent = new Intent(MainActivity.this, FirstService.class); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } public void test01(View view) { mService.info(); } private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { DebugLog.e("断开连接"); mService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { DebugLog.e("连接成功"); mService = ((FirstService.FirstBinder) service).getService(); } }; @Override protected void onDestroy() { super.onDestroy(); DebugLog.e("MainActivity被销毁"); unbindService(mServiceConnection); }打印日志:
E/FirstService.java(5032): [onBind:15]绑定服务被执行
E/MainActivity.java(5032): [onServiceConnected:40]连接成功
E/FirstService.java(6342): [onUnbind:40]解绑服务被执行
E/FirstService.java(6342): [onDestroy:35]服务被销毁
A应用访问B应用的Service
第一种:通过指定Action启动服务
<service android:name="com.leo.myservice.FirstService" android:permission="com.permission.xxx.service" > <intent-filter> <action android:name="com.intent.action.XxxService" /> </intent-filter></service>然后咱们就可以在A应用中声明权限后访问B应用的服务了:context.startService(new Intent("com.intent.action.XxxService"));
第二种:通过AIDL绑定服务
package com.leo.aidl;interface IAIDLService{ // 获取步数 int getSteps();}新建一个服务AidlService,并实现.aidl文件中声明的所有抽象方法,然后onBind方法返回一个Binder实例。
public class AidlService extends Service { @Override public void onCreate() { super.onCreate(); DebugLog.e("远程服务被激活"); } @Override public void onDestroy() { super.onDestroy(); DebugLog.e("远程服务被销毁"); } @Override public boolean onUnbind(Intent intent) { DebugLog.e("解绑远程服务"); return super.onUnbind(intent); } @Override public IBinder onBind(Intent intent) { DebugLog.e("绑定远程服务"); return mBinder; } private final IAIDLService.Stub mBinder = new IAIDLService.Stub() { @Override public int getSteps() throws RemoteException { return 10000; } };}接着在manifest文件中注册该远程服务:
<service android:name="com.leo.myservice.AidlService" android:exported="true" > <intent-filter> <action android:name="com.intent.action.remoteService" /> </intent-filter></service>A应用(客户端) :导入B应用中的.aidl文件,且aidl接口文件所在的包与服务端的必须相同
public class MainActivity extends Activity { private IAIDLService mService; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // 绑定远程服务XxxService Intent intent = new Intent("com.intent.action.remoteService"); bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE); } // Button监听 public void test01(View view) { try { int steps = mService.getSteps(); DebugLog.e("steps = " + steps); } catch (RemoteException e) { e.printStackTrace(); } } private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceDisconnected(ComponentName name) { DebugLog.e("断开连接"); mService = null; } @Override public void onServiceConnected(ComponentName name, IBinder service) { DebugLog.e("连接成功"); mService = IAIDLService.Stub.asInterface(service); } }; @Override protected void onDestroy() { super.onDestroy(); unbindService(mServiceConnection); }}服务端打印日志:
E/AidlService.java(27821): [onCreate:16]远程服务被激活
E/AidlService.java(27821): [onBind:33]绑定远程服务
客户端打印日志:
E/MainActivity.java(26711): [onServiceConnected:47]连接成功
接着点击Button,可以看到步数也被打印了:
E/AidlService.java(27821): [onDestroy:22]远程服务被销毁
IntentService
在讲IntentService之前,先来了解一下Handler和HandlerThread。thread.start();// 启动HandlerThread
mServiceHandler = new ServiceHandler(mServiceLooper);//绑定HandlerThread
public class FirstIntentService extends IntentService { @Override public void onCreate() { super.onCreate(); DebugLog.e("服务被激活"); } public FirstIntentService() { super("MyIntentService"); } int i = 0; @Override protected void onHandleIntent(Intent intent) { DebugLog.e("pid = " + Thread.currentThread().getId()); DebugLog.e("任务执行开始..."); i = 0; try { while (i < 3) { Thread.sleep(1000); i++; DebugLog.e("i = " + i + "s"); } } catch (InterruptedException e) { e.printStackTrace(); } DebugLog.e("任务执行完成..."); } @Override public void onDestroy() { super.onDestroy(); DebugLog.e("服务被销毁"); }}MainActivity添加两个Button进行测试:一个启动服务、一个测试服务是否存在
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); DebugLog.e("pid = " + Thread.currentThread().getId()); } public void button1(View view) { startService(new Intent(this, FirstIntentService.class)); } public void button2(View view) { boolean isServiceRunning = ServiceUtils.isServiceRunning(this, FirstIntentService.class.getName()); DebugLog.e("isServiceRunning = " + isServiceRunning); }}点两次按钮,打印日志如下:
E/MainActivity.java(19249): [onCreate:18]pid = 1E/FirstIntentService.java(19249): [onCreate:13]服务被激活E/FirstIntentService.java(19249): [onHandleIntent:24]pid = 2236E/FirstIntentService.java(19249): [onHandleIntent:25]任务执行开始...E/FirstIntentService.java(19249): [onHandleIntent:31]i = 1sE/FirstIntentService.java(19249): [onHandleIntent:31]i = 2sE/FirstIntentService.java(19249): [onHandleIntent:31]i = 3sE/FirstIntentService.java(19249): [onHandleIntent:36]任务执行完成...E/FirstIntentService.java(19249): [onHandleIntent:24]pid = 2236E/FirstIntentService.java(19249): [onHandleIntent:25]任务执行开始...E/FirstIntentService.java(19249): [onHandleIntent:31]i = 1sE/MainActivity.java(19249): [button2:28]isServiceRunning = trueE/FirstIntentService.java(19249): [onHandleIntent:31]i = 2sE/FirstIntentService.java(19249): [onHandleIntent:31]i = 3sE/FirstIntentService.java(19249): [onHandleIntent:36]任务执行完成...E/FirstIntentService.java(19249): [onDestroy:42]服务被销毁E/MainActivity.java(19249): [button2:28]isServiceRunning = false从日志中可以看到:onHandleIntent中的线程ID与主线程中的是不一样的,这样验证了IntentService消息处理是在非UI线程中进行的,而且是在同一线程中执行; 同时消息一旦处理完服务也随之被销毁了。
总结: