基本介绍
Service是一个应用程序组件,四大组件之一,它能够在后台执行一些耗时较长的操作,并且不提供用户界面。服务能被其它应用程序的组件启动,即使用户切换到另外的应用时还能保持后台运行。此外,应用程序组件还能与服务绑定,并与服务进行交互,甚至能进行进程间通信(IPC)。
使用方式
Service有常见的两种启动方式,Started 和Bound 方式。
Started 方式
如果一个应用程序组件(比如一个activity)通过调用startService()来启动服务,则该服务就是被“started”了。
一旦被启动,服务就能在后台一直运行下去,即使启动它的组件已经被销毁了。
通常,started的服务执行单一的操作并且不会向调用者返回结果。比如,它可以通过网络下载或上传文件。当操作完成后,服务应该自行终止。
执行顺序: onCreate() -> onStartCommand() ->onDestroy();
销毁方式 stopService()
区别: startService()之后,无论启动的组件是否仍然存在,没有调用stopService()方法,Service仍然存在。
/**
* 启动服务
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:20
*/
public void startService(View view) {
Intent intent = new Intent(this, MyService.class);
startService(intent);
}
/**
* 关闭服务
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:20
*/
public void stopService(View view) {
Intent intent = new Intent(this, MyService.class);
stopService(intent);
}
Bound 方式
如果一个应用程序组件通过调用bindService()绑定到服务上,则该服务就是被“bound”了。
bound服务提供了一个客户端/服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至可以利用进程间通信(IPC)跨进程执行这些操作。
绑定服务的生存期和被绑定的应用程序组件一致。 多个组件可以同时与一个服务绑定,不过所有的组件解除绑定后,服务也就会被销毁。
执行顺序: onCreate() -> onBind() ->onDestroy();
销毁方式 unbindService()
注意:通过unbindService()取消Service需要判定是否bind,否则报异常
区别: bindService()即将调用绑定的组件与这个Service捆绑在一起,组件销毁了Service也被销毁,类似从属关系。
Bound方式Service与Activity通讯
1.MyService中的onBind()返回IBind子类实例。
2.ServiceConnection的onServiceConnected()方法拿出IBinder,向下强转为MyService中的IBind子类,即可对Service进行操作。
private ServiceConnection mServiceConn = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i("info", "onServiceConnected: ==++ 服务连接");
MyService.MyBinder myBinder = (MyService.MyBinder) service;
myBinder.doSomething();
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.i("info", "onServiceDisconnected: ==++ 服务取消连接");
}
};
// 标记服务是否绑定
private boolean isBind = false;
/**
* 绑定服务
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:27
*/
public void bindService(View view) {
Intent intent = new Intent(this, MyService.class);
bindService(intent, mServiceConn, BIND_AUTO_CREATE);
isBind = true;
}
/**
* 取消绑定服务
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:28
*/
public void unbindService(View view) {
if (isBind) {
isBind = false;
unbindService(mServiceConn);
}
}
MyService
/**
* 自定义Service
*
* @author fengzhen
* @version 1.0, 2017/7/21
*/
public class MyService extends Service {
@Override
public void onCreate() {
Log.i("info", "onCreate: ==++ 服务创建");
Log.i("info", "onCreate: ==++ 当前线程:" + Thread.currentThread().getName());
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i("info", "onStartCommand: ==++ 服务启动");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.i("info", "onDestroy: ==++ 服务销毁");
super.onDestroy();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
Log.i("info", "onBind: ==++ 绑定服务");
return new MyBinder();
}
public class MyBinder extends Binder {
public void doSomething() {
Log.i("info", "doSomething: ==+++ 做具体的事");
}
}
}
运行线程
通过验证可以发现,Service和Activity一样,运行在主线程,所以在使用是需要创建一个新的线程完成服务的工作。
也可以使用其子类:IntentService
IntentService
创建一个缺省的工作(worker)线程,它独立于应用程序主线程来执行所有发送到onStartCommand()的intent。
创建一个工作队列,每次向你的onHandleIntent()传入一个intent,这样你就永远不必担心多线程问题了。
在处理完所有的启动请求后,终止服务,因此你就永远不需调用stopSelf()了。
提供缺省的onBind()实现代码,它返回null。
提供缺省的onStartCommand()实现代码,它把intent送入工作队列,稍后会再传给你的onHandleIntent()实现代码。
/**
* Service服务扩展类
*
* @author fengzhen
* @version v1.0, 2017/7/21
*/
public class MyIntentService extends IntentService {
/**
* Creates an IntentService. Invoked by your subclass's constructor.
* <p>
* Used to name the worker thread, important only for debugging.
*/
public MyIntentService() {
super("MyIntentService");
}
/**
* IntentService从缺省的工作线程中调用本方法,并用启动服务的intent作为参数
* 本方法返回后,IntentService将适时终止这个服务。
* <p>
* 再次方法操作需要在子线程做的,使用循环的方式,直到任务完成
*
* @author fengzhen
* @version v1.0, 2017/7/21 17:05
*/
@Override
protected void onHandleIntent(Intent intent) {
Log.i("info", "onCreate: ==++ 当前线程:" + Thread.currentThread().getName());
int i = 0;
while (i < 10) {
i++;
// doSomething
}
}
}
进程间通信(IPC)
使用AIDL来进行进程间通信(IPC)
AIDL(Android Interface Definition Language):Android接口定义语言
1.更改Service在xml配置
<service android:name=".MyService"
android:process=":remote">
<intent-filter>
<action android:name="com.hftsoft.servicedemo.MyAidlInterface"/>
</intent-filter>
</service>
2.创建AIDL文件
这里参数类型只能使用basecTypes中的所有参数类型
AS创建AIDL文件只有需要点击 mudel 旁小锤子图标 Make Project (Ctrl + f9)
interface MyAidlInterface {
/**
* Demonstrates some basic types that you can use as parameters
* and return values in AIDL.
*/
void basicTypes(int anInt, long aLong, boolean aBoolean, float aFloat,
double aDouble, String aString);
/**
* 自定义简单方法
*/
String getString(int a);
}
3.绑定Activity中实现
private MyAidlInterface mMyAidlInterface;
/**
* PIC Conn
*
* @author fengzhen
* @version v1.0, 2017/7/21 18:16
*/
private ServiceConnection mServiceConnRemote = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mMyAidlInterface = MyAidlInterface.Stub.asInterface(service);
try {
String string = mMyAidlInterface.getString(5);
Log.i("info", "onServiceConnected: ==++" + string);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
// 标记服务是否绑定
private boolean isBind = false;
/**
* 绑定服务 IPC
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:27
*/
public void bindService(View view) {
Intent intent = new Intent("com.hftsoft.servicedemo.MyAidlInterface");
intent.setPackage(this.getPackageName());
bindService(intent, mServiceConnRemote, BIND_AUTO_CREATE);
isBind = true;
}
/**
* 取消绑定服务 IPC
*
* @author fengzhen
* @version v1.0, 2017/7/21 15:28
*/
public void unbindService(View view) {
if (isBind) {
isBind = false;
unbindService(mServiceConnRemote);
}
}