Android四大组件之:service

Service

服务: 长期后台运行的没有界面的组件

android应用:什么地方需要用到服务?

天气预报:后台的连接服务器的逻辑,每隔一段时间 获取最新的天气信息

股票显示:后台的连接服务器的逻辑,每隔一段时间 获取最新的股票信息

mp3播放器: 后台长期的播放音乐。

 

长期后台运行的组件, 不要在activity开启子线程。

应该是创建服务,在服务里面开启子线程。

服务的目的:

1.长期后台运行。

2.提高进程的优先级,系统不容易回收掉进程,即便回收了,内存充足的时候,把进程重新创建。

 

默认情况,如果没有显示的指定service所运行的进程, Serviceactivity是运行在当前app所在进程的main thread(UI主线程)里面,

service里面不能执行耗时的操作(网络请求,拷贝数据库,大文件 ),在子线程中执行 new Thread(){}.start();

进程管理

android系统进程管理是按照一定的规则的:

1.应用程序一旦被打开 通常情况下关闭(清空任务栈)后进程不会停止。方面下一次快速启动。带来内存不足的问题。

2.Android系统有一套 内存清理机制。 按照优先级去回收系统的内存。

 

进程分为5个等级的优先级:(从高到低)

1.Foreground process 前台进程  用户正在玩的应用程序对应的进程

2.Visible process 可视进程 用户仍然可以看到这个进程的界面。

3.Service process服务进程  应用程序有一个服务组件在后台运行。

4.Background process 后台进程  应用程序没有服务在运行 并且最小化 (activity onstop

5.Empty process 空进程 没有任何运行的activity, 任务栈空了

 

开启服务的方法

一、采用start的方式开启服务       

开启服务: onCreate()--> onStartCommand()onStart()过时了)  ---> onDestory();

如果服务已经开启,不会重复的执行onCreate(), 而是会调用onStart()和 onStartCommand();

服务停止的时候 onDestory().

服务只会被停止一次

 

二、服务还有一种开启方式,绑定的方式开启服务。

onCreate() --->onBind();--->onunbind()-->onDestory();

绑定服务不会调用onstart或者onstartcommand方法;

 

混合调用的服务的生命周期:

服务长期后台运行,又想调用服务的方法:

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

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

3.unbind解除绑定服务

4.stopService停止服务。

 

三、两种开启服务方法的区别。

 

start方式开启服务。 一旦服务开启跟调用者(开启者)就没有任何关系了。

开启者退出了,开启者挂了,服务还在后台长期的运行。

开启者没有办法去调用服务里面的方法。(美国的司法独立)

 

bind的方式开启服务,绑定服务,调用者挂了,服务也会跟着挂掉。不求同时生,但求同时死。开启者可以调用服务里面的方法。

 

本地服务与远程服务

本地服务:调用者和服务在同一个工程代码里面。

绑定本地服务调用方法的步骤:

1.在服务的内部创建一个内部类 提供一个方法,可以间接调用服务的方法

private class MiddlePerson extends Binder implements IMiddlePerson{}

2.实现服务的onbind方法,返回的就是中间人 MiddlePerson

3.activity 绑定服务。bindService();

4.在服务成功绑定的时候 会执行一个方法 onServiceConnected 传递过来一个 IBinder对象

5.强制类型转化 调用接口里面的方法。

 

远程服务:调用者和服务在不同的工程代码里面。

绑定远程服务调用方法的步骤:

1.在服务的内部创建一个内部类 提供一个方法,可以间接调用服务的方法

2.把暴露的接口文件的扩展名改为aidl文件 去掉访问修饰符 public

private class MiddlePerson extends IMiddlePerson.Stub{}  IPC的子类

3.实现服务的onbind方法,返回的就是中间人 IMiddlePerson

4.activity 绑定服务。bindService();

5.在服务成功绑定的时候 会执行一个方法 onServiceConnected 传递过来一个 IBinder对象

 

aidlandroid interface definition language  安卓接口定义语言

aidl文件都是公有的,没有访问权限修饰符

IPC: inter process communication 进程间通讯

IntentService

IntentServiceService类的子类,用来处理异步请求。客户端可以通过startService(Intent)方法传递请求给IntentService

 

IntentServiceonCreate()函数中通过HandlerThread单独开启一个线程来处理所有Intent请求对象(通过startService的方式发送过来的)

所对应的任务,这样以免事务处理阻塞主线程。执行完所一个Intent请求对象所对应的工作之后,如果没有新的Intent请求达到,则自动

停止Service;否则执行下一个Intent请求所对应的任务。

 

IntentService在处理事务时,还是采用的Handler方式,创建一个名叫ServiceHandler的内部Handler,并把它直接绑定到HandlerThread

所对应的子线程。 ServiceHandler把处理一个intent所对应的事务都封装到叫做onHandleIntent的虚函数;因此我们直接实现虚函数

onHandleIntent,再在里面根据Intent的不同进行不同的事务处理就可以了。

 

另外,IntentService默认实现了Onbind()方法,返回值为null

  使用IntentService需要两个步骤:

  1、写构造函数

  2、实现虚函数onHandleIntent,并在里面根据Intent的不同进行不同的事务处理就可以了。

好处:处理异步请求的时候可以减少写代码的工作量,比较轻松地实现项目的需求

注意:IntentService的构造函数一定是参数为空的构造函数,然后再在其中调用super("name")这种形式的构造函数。因为Service的实例化是系统

来完成的,而且系统是用参数为空的构造函数来实例化Service

 

public class MyIntentService extends IntentService {

final static String TAG="robin";

 public MyIntentService() {

  super("com.lenovo.robin.test.MyIntentService");

  Log.i(TAG,this+" is constructed");

 }

 @Override

 protected void onHandleIntent(Intent arg0) {

  Log.i(TAG,"begin onHandleIntent() in "+this);

  try {

   Thread.sleep(10*1000);

  } catch (InterruptedException e) {

     e.printStackTrace();

  }

  Log.i(TAG,"end onHandleIntent() in "+this);

 }

 public void onDestroy()

 {

  super.onDestroy();

  Log.i(TAG,this+" is destroy");

 }

}

 

启动MyIntentServic的代码片段

   Intent intent=new Intent(this,MyIntentService.class);

   startService(intent);

Aidl

全称是:Android Interface Define Language

Android每个应用程序都可以有自己的进程在写UI应用的时候经常要用到Service. 在不同的进程中怎样传递对象呢显然

Java中不允许跨进程内存共享.因此传递对象只能把对象拆分成操作系统能理解的简单形式以达到跨界对象访问的目的J2EE,

采用RMI的方式可以通过序列化传递对象Android则采用AIDL的方式理论上AIDL可以传递Bundle,实际上做起来却比较麻烦。

 

AIDL(AndRoid接口描述语言)是一种借口描述语言编译器可以通过aidl文件生成一段代码,通过预先定义的接口达到两个进程内部

通信进程的目的如果需要在一个Activity访问另一个Service中的某个对象需要先将对象转化成AIDL可识别的参数(可能是多个参数), 

然后使用AIDL来传递这些参数在消息的接收端使用这些参数组装成自己需要的对象.AIDLIPC的机制和COMCORBA类似是基于接口的,
但它是轻量级的。它使用代理类在客户端和实现层间传递值
如果要使用AIDL, 

需要完成2件事情: 1. 引入AIDL的相关类.; 2. 调用aidl产生的class.

 

AIDL的创建方法:

 

AIDL语法很简单,可以用来声明一个带一个或多个方法的接口,也可以传递参数和返回值。 由于远程调用的需要这些参数和返回值并不是任何类型.

 

下面是些AIDL支持的数据类型:

 

1. 不需要import声明的简单Java编程语言类型(int,boolean

2. String, CharSequence不需要特殊声明

3. List, MapParcelables类型这些类型内所包含的数据成员也只能是简单数据类型, String等其他比支持的类型.

 

A进程要去调用B进程中的service时,并实现通信,我们通常都是通过AIDL来操作的。

 

A工程:

首先我们在net.blogjava.mobile.aidlservice包中创建一个RemoteService.aidl文件,在里面我们自定义一个接口,含有方法get

ADT插件会在gen目录下自动生成一个RemoteService.java文件,该类中含有一个名为RemoteService.stub的内部类,该内部类中

含有aidl文件接口的get方法。

 

说明一:aidl文件的位置不固定,可以任意

然后定义自己的MyService类,在MyService类中自定义一个内部类去继承RemoteService.stub这个内部类,实现get方法。在onBind方法

中返回这个内部类的对象,系统会自动将这个对象封装成IBinder对象,传递给他的调用者。

 

其次需要在AndroidManifest.xml文件中配置MyService类,代码如下:

<!-- 注册服务 -->  

<service android:name=".MyService"> 

   <intent-filter> 

   <!--  指定调用AIDL服务的ID  --> 

       <action android:name="net.blogjava.mobile.aidlservice.RemoteService" /> 

    </intent-filter> 

</service>

为什么要指定调用AIDL服务的ID,就是要告诉外界MyService这个类能够被别的进程访问,只要别的进程知道这个ID

正是有了这个ID,B工程才能找到A工程实现通信。

说明:AIDL并不需要权限

 

B工程:

      首先我们要将A工程中生成的RemoteService.java文件拷贝到B工程中,在bindService方法中绑定aidl服务

      绑定AIDL服务就是将RemoteServiceID作为intentaction参数。

      说明:如果我们单独将RemoteService.aidl文件放在一个包里,那个在我们将gen目录下的该包拷贝到B工程中。如果我们将

RemoteService.aidl文件和我们的其他类存放在一起,那么我们在B工程中就要建立相应的包,以保证RmoteService.java文件的

报名正确,我们不能修改RemoteService.java文件

           bindService(new Inten("net.blogjava.mobile.aidlservice.RemoteService"), 

serviceConnection, Context.BIND_AUTO_CREATE); 

       ServiceConnectiononServiceConnected(ComponentName name, IBinder service)方法中的service参数就是A工程中MyService

中继承了RemoteService.stub类的内部类的对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值