您的位置:首页 > 移动开发 > Android开发

Android四大组件之Service

2015-12-13 21:41 260 查看
服务Service

服务的入门?

为什么使用服务?如果仅仅使用进程的换,又和服务有什么区别?

如果我们使用activity,在其中启动一个线程,如果关闭了activity,那么这个进程就是一个空进程,

我们都知道空进程的优先级是很低的,当内存不足的时候很容易被回收,这里如果我们使用了service,即使我们关闭了

activity,这个进程在service里面,它就属于是一个服务进程,他的优先级比较高一般情况下不会被回收,即使被回收了,

在内存控件又充足的时候还会被重新开启!!!

##进程的优先级

* Foreground process

> 前台进程: 用户正在操作的应用程序所在的进程就是前台进程

* Visible process

> 可视进程: 用户已经不能操作这个应用程序了,但是界面用户仍然可以看到

* Service process

> 服务进程: 应用程序有一个服务代码正在运行

* Background process

> 后台进程: 应用程序有界面,但是界面被用户最小化(home)

* Empty process

> 空进程: 应用程序没有任何运行的Activity,service.

前台进程>可视进程>服务进程>后台进程>空进程

##服务的应用场景

> 长期后台运行,没有界面的组件.

>

> 1. 监视一个硬件是否被插入

> 2. 连接服务器刷新最新的数据.

> 3. 定时的轮询

注意: 服务是运行在主线程里面(main), 不可以直接在服务里面编写耗时的逻辑.

一:创建一个service的步骤

1,创建一个类继承service,重写oncreate()方法(//服务第一次被创建调用的代码)

2,在清单文件中配置<service name="包类名">

3,在MainActivity中开启服务(startService(intent))

-------------------------------------------------------------------------------

重点:两种启动服务的方式

方式一: 1,开启服务之后,就和activity没有直接的关系了,就算activity关闭了,这个服务还是存在的.

2,如果要在activity里面传递数据给service,每次都需要创建一个意图对象,携带数据信息发送给

activity,然后service会在它的onStartConnand()方法里面,通过getIntent()后去意图,在获取数据,

最后更具数据的不同,做相对应的操作.

缺陷:这个方式的缺点是,我们不能调用service里面的方法(因为他不会返回服务的引用对象)只能通过intent来传递,再到service

的onstartCommand()里面获取意图在进行相对应的操作,这样达不到服务间的同学

(掌握)方式二:再讲这个方法之前需要理解的几个概念

a,在service里面的IBinder是法定代理人对象他是一个接口(Binder它的一个子类)

onBinder方法返回一个IBinder对象

b,我们在service里面编写一个内部类MyBinder extends Binder implements IService

重写接口中需要我们实现的方法.,最后在onBind(),返回这个代理人对象(activity里面接受)

这里需要我们实现的方法其实就是,代理人调用service里面的内部方法

注意:这里我们把方法写在接口里面这样需要我们实现的方法就暴露给我们不需要的它就直接隐藏了

c,在Activity代码中采用方式二的绑定服务

意图 ,通讯频道,如果服务不存在,会把服务创建起来

bindService(intent,new MyConn,BBIND_AUTO_CREATE);

d,serviceConnection的实现类里面有一个方法,获取service里面返回给我们的代理人

具体实现:创建一个Myconn类implements serviceConnection再实现未实现的方法

链接成功了就会拿到(代理人的引用)

public void onServiceConnected(ComponentName name, IBinder service)

为了避免方式一的弊端,(不调用service里面的方法),所以我们学习一种新的开启方式

(1) bindService(intent,conn,BIND_AUTO_CREATE);

这种方式需要在service里面写一个代理人

//当服务被成功连接的时候调用的方法

private class MyBinder extends Binder implements IService{

@Override

public void callMethodInService() {

methodInService();

}

}

然后返回代理人

@Override

public IBinder onBind(Intent intent) {

System.out.println("onbind");

return new MyBinder();

}

(2)在MainActivity里面去创建链接 通过实现类serviceConnection();

自己创建一个MyConn 实现这个类,然后当链接成功的时候里面的一个方法会

返回我们刚刚在service创建的new MyBinder(); (我把它称为法定代理人)

private class MyConn implements extends Binder implements ServiceConnection{

//当服务被成功连接的时候调用的方法

@Override

public void onServiceConnected(ComponentName name, IBinder service) {

System.out.println("在Activity得到了服务返回的代理人对象,IBinder");

myBinder = (MyBinder) service;

}

//当服务失去连接的时候调用的方法.

@Override

public void onServiceDisconnected(ComponentName name) {

}

}

(3),在上面的service里面我选择去

private class MyBinder extends Binder implements XXXXXX

我们可以让自己的MyBinder实现一个接口,这个接口的主要作用是暴露出我们想让别人看见的方法,

这样就可以保护一些特殊的方法,调用者就看不见了

二、绑定服务的生命周期

绑定服务(bindService)和前面第一次所学的(startService)启动方式不同,那么服务的生命周期是不同的

直接调用bindService() 如果服务不存在, 会执行oncreate--->onbind,服务的onstart和onstartcommand方法不会被执行.

并且通过bindService方式启动服务的话,如果想停掉服务直接调用stopService()方法是没有用的,比如执行

unbindService()方法, 然后它的生命周期方法会执行 onunbind()--->ondetroy()

以下是一些细节问题,要注意:

多次绑定服务,服务只会被创建一次,oncreate方法只会被执行一次

多次绑定服务,onbind方法不会被重复调用.

在实际开发的时候,如果需要调用服务的方法,就绑定服务,只能绑定一次

服务只可以被解绑一次,如果用同一个conn对象多次解绑,服务会抛出异常!

不求同时生,但求同时死. 如果开启者(Activity)退出了, 服务也会跟着挂掉.

但是如果service某种情况挂掉了,activity不会死掉,所以并不是完全的同时生,同时死

bindService开启的服务在系统设置界面看不到的.

三、混合启动服务

如果将我们前面学习的startService 和 bindService,两个方法结合起来用的话,会产生新的效果

应用场景: 为了保证服务又能长期后台运行,又能调用到服务里面的方法 就采用混合的方式开启服务.

如果使用混合服务,请严格按照以下步骤:

1. start的方式开启服务 (保证服务长期后台运行)

2. bind的方式绑定服务 (调用服务的方法)

3. unbind的方式解除绑定服务

4. stop的方式停止服务

四,本地的服务和远程服务 (重点需要掌握)

* 本地服务 local service

> 服务的代码在当前应用程序的内部

* 远程服务 remote service

> 服务的代码在另外一个应用程序里面

##重要概念(面试用得到)

* 进程

> 操作系统分配的独立的内存空间.

(不同的内存空间是相互独立的如果想要相互访问就需要用到IPC技术) 运行在用户空间

* IPC 技术 //里面是没有上下文,

> inter process communication 进程间通讯

系统底层下有一块公共的内存空间,通过这个内存空间(BinderQ驱动)就可以实现通讯

* aidl 技术

> android interface definition language

安卓接口定义语言(谷歌给我们包装的,不用知道细节,就知道怎么使用了IPC了)

五,远程服务的流程(AIDL)

远程服务

(需要配置action 隐式跳转)

1,和本地服务通讯的编写代码一样.

2,远程服务只是把我们接口定义的需要暴露的方法文件改成".aidl"格式的.

IService.java 改名字为---> IService.aidl

3,找到接口文件的具体目录,并改成aidl格式,而且,这种格式不需要任何权限修饰符(权限访问java里面才有)

再把IService.aidl 里面所有的public 修饰符给去掉!

4,把原来的代理人原来代理人MyBinder extend Binder implemet IService--> extends IService.Stub()

然后eclipse会要求你重写 第二步接口里面定义的方法,在这个方法里面再去调用服务的方法

5,最后需要记得在清单文件中配置service标签,并且要设置一个action!!!!如果不设置action,

那么问题来了,调用者怎么调用?

例子:

<service android:name="xxxxxxxxxxxxxxxxxxxxxxxx" >

<intent-filter >

<action android:name="xxxxxxxxxxxxx"/>

</intent-filter>

</service>

##重要概念

* 进程

> 操作系统分配的独立的内存空间.(不同的内存空间是相互独立的如果想要相互访问就需要用到IPC技术) 运行在用户空间

* IPC 技术 //里面是没有上下文,

> inter process communication 进程间通讯 系统底层下有一块公共的内存空间,通过这个内存空间(BinderQ驱动)就可以实现通讯

* aidl 技术

> android interface definition language 安卓接口定义语言(谷歌给我们包装的,不用知道细节,就知道怎么使用了IPC了)

----------------------------------------------------------------------------------------------------

调用者

(调用者需要在MainAction里面设置setAction的远程服务的action)

6,先把远程服务的.aidl文件拷贝到本地应用程序的工程目录下

(需要创建一个包,报名和.aidl的所在的远程服务的包名完全相同)

7, 然后在activity的连接实现类里面获取返回来的代理人

iService = IService.Stub.asInterface(service);得到远程服务的代理对象

内部类的这个方法实现了获取因为这个方法就是service返回的MyBinder

(别乱了,MyBinder extends IBinder ,又因为IBinder需要实现的方法太多所以一般继承他的子类Binder

这个类是谷歌帮我们封装好的,)

8,通过代理对象调用远程服务的方法.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: