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

Android-服务

2015-10-07 22:11 639 查看

Android-服务

概述

Service(服务)是一个没有用户界面的在后台运行执行耗时操作的应用组件。其他应用组件能够启动Service,并且当用户切换到另外的应用场景,Service将持续在后台运行。

另外,一个组件能够绑定到一个service与之交互(IPC机制),例如,一个service可能会处理网络操作,播放音乐,操作文件I/O或者与内容提供者(content provider)交互,

所有这些活动都是在后台进行。

服务分为:本地服务和远程服务

* 本地服务:指的是服务和启动服务的activity在同一个进程中

* 远程服务:指的是服务和启动服务的activity不在同一个进程中

服务的启动

服务有两种启动方式:

通过startService()启动的服务处于“启动的”状态,一旦启动,service就在后台运行,即使启动它的应用组件已经被销毁了。

通常started状态的service执行单任务并且不返回任何结果给启动者。比如当下载或上传一个文件,当这项操作完成时,service应该停止它本身。

还有一种“绑定”状态的service,通过调用bindService()来启动,一个绑定的service提供一个允许组件与service交互的接口,可以发送请求、获取返回结果,还可以通过夸进程通信来交互(IPC)。

绑定的service只有当应用组件绑定后才能运行,多个组件可以绑定一个service,当调用unbind()方法时,这个service就会被销毁了。并且,当启动服务的进程挂掉时,这个“绑定的”服务也会挂掉。

-> startService()启动

intent = new Intent(this, MyService.class);
startService(intent);

stopService(intent);  //关闭服务


-> bindService()启动

intent = new Intent(this, MyService.class);
conn = new MyServiceConn();
bindService(intent, conn, BIND_AUTO_CREATE);

unbindService(conn); //解绑服务

class MyServiceConn implements ServiceConnection{

//服务连接成功时,此方法调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub

}

//服务失去连接时,此方法调用
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub

}

}


对于远程服务:

它只能隐式启动,类似隐式启动Activity,在清单文件中配置Service标签时,必须配置intent-filter子节点,并指定action子节点。启动时当然也要一一对应

例如:

Intent intent = new Intent();
intent.setAction("com.itheima.remote");
stopService(intent);
or
bindService(intent, conn, BIND_AUTO_CREATE);


startService() 与 bindService()的混合调用

有时我们会有这种需求,服务必须要能独立运行与后台(不与activity共生死), 且又需要利用bindService()来启动。

这时 服务的启动必须要遵循一定的顺序, 不然会出问题!

->先开始、再绑定,先解绑、再停止

服务的生命周期相关方法

由于服务无前台界面,因此就不存在焦点及其相关方法。

在第一次开启服务时会调用onCreate() 和 onStartConmand(); 如果已经开启, 再次开启的话只会调用 onStartConmand()。



IntentService

它是Service的一个子类。

IntentService使用队列的方式将请求的Intent加入队列,然后开启一个worker thread(线程)来处理队列中的Intent,

对于异步的startService请求,IntentService会处理完成一个之后再处理第二个,每一个请求都会在一个单独的worker thread中处理,不会阻塞应用程序的主线程。

由于一般我们是不能再Service中进行一些耗CPU和耗时操作(下载什么的), 这些耗时操作我们一般都会开启一个子线程来做。

但是如果我们继承IntentService,由于这个类在处理事务时就是开启了线程来处理的,因此,我们可以将耗时操作直接放在服务里,就不用再手动开启子线程了。

example:
public class HelloIntentService extends IntentService {

/**
* A constructor is required, and must call the super IntentService(String)
* constructor with a name for the worker thread.
*/
public HelloIntentService() {
super("HelloIntentService");
}

/**
* The IntentService calls this method from the default worker thread with
* the intent that started the service. When this method returns, IntentService
* stops the service, as appropriate.
*/
@Override
protected void onHandleIntent(Intent intent) {
// Normally we would do some work here, like download a file.
// For our sample, we just sleep for 5 seconds.
long endTime = System.currentTimeMillis() + 5*1000;
while (System.currentTimeMillis() < endTime) {
synchronized (this) {
try {
wait(endTime - System.currentTimeMillis());
} catch (Exception e) {
}
}
}
}
}


访问服务中的方法

Service对象是由系统创建的(我们是弄不出来它的)。因此我们在activity中是不可能直接访问到Service的方法的。这可如何是好呢?

为了访问到Service对象的方法,我们需要一个中间人对象-> IBinder

这个对象在服务的onBind()方法调用时会被返回。而在bindService()方法调用时,我们可以通过其ServiceConnection参数的onServiceConnected()方法拿到那个被返回的IBinder对象。

原理就是->利用这个中间人IBinder来访问服务中的方法。

具体做法:

public interface PublicBusiness {

void QianXian();
}

public class LeaderService extends Service {

@Override
public IBinder onBind(Intent intent) {
// 返回一个Binder对象,这个对象就是中间人对象
return new ZhouMi();
}

class ZhouMi extends Binder implements PublicBusiness{
public void QianXian(){
banZheng();
}

public  void daMaJiang(){
System.out.println("陪李处打麻将");
}
}

public void banZheng(){
System.out.println("李处帮你来办证");
}
}

public class MainActivity extends Activity {

private Intent intent;
private MyServiceConn conn;
PublicBusiness pb;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
intent = new Intent(this, LeaderService.class);
conn = new MyServiceConn();
//绑定领导服务
bindService(intent, conn, BIND_AUTO_CREATE);
}

public void click(View v){
//调用服务的办证方法
pb.QianXian();
}

class MyServiceConn implements ServiceConnection{

//连接服务成功,此方法调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
pb = (PublicBusiness) service;
}

@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub

}

}
}


访问远程服务中的方法

上面的方式只能访问本地服务中的方法。这种方式就不能用来访问远程服务中的方法。

这是因为,我们在上面 pb = (PublicBusiness) service; 进行了强转, 而在不同的进程中你可能这样直接强转成功吗?????

解决办法-> AIDL(Android interface definition language)

它用于进程间通信

使用步骤:

1. 把远程服务的方法抽取成一个单独的接口java文件(这里叫他PublicBusiness)

2. 把接口java文件的后缀名改成aidl

3. 在自动生成的PublicBusiness.java文件中,有一个静态抽象类Stub,它已经继承了binder类,实现了PublicBusiness接口,这个类就是新的中间人

4. 把这个生成的aidl文件复制到要进行访问这个服务的进程代码去,并且在复制时应注意aidl文件所在的包名必须跟提供服务项目中aidl所在的包名一致

关键:

在访问远程服务项目中,强转中间人对象时,直接使用Stub.asInterface()进行强转:

public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
PublicBusiness pb = Stub.asInterface(service);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android 服务