第五章 Service 应用

Preview:

DESCRIPTION

第五章 Service 应用. 本章主要内容. 什么是 Service. 顾名思义, Service 即“服务”的意思, Activity 拥有前台运行的用户界面,而 Service 不能自己运行,需要通过某个 Activity 或者其他 Context 对象来调用。 在默认情况下, Service 运行在应用程序进程的主线程之中,但如果需要在 Service 中处理一些诸如连接网络等耗时操作时,就应该将其放在单独的线程中进行处理,避免阻塞用户界面。 - PowerPoint PPT Presentation

Citation preview

第五章 Service 应用

本章主要内容

什么是 Service

跨进程调用

Service 实例——音乐播放器

顾名思义, Service 即“服务”的意思, Activity 拥有前台运行的用户界面,而 Service 不能自己运行,需要通过某个Activity 或者其他 Context 对象来调用。

在默认情况下, Service 运行在应用程序进程的主线程之中,但如果需要在 Service 中处理一些诸如连接网络等耗时操作时,就应该将其放在单独的线程中进行处理,避免阻塞用户界面。

可以通过 Context.startService() 和 Context.bindService()两种方式来启动 Service 。

什么是 Service

什么是 Service

1. 使用 Context.startService() 启动Service

步骤如下:Context.startService—>onCreate()—>onStart()—>Service running—

>onDestroy()—>Service 如果 Service 处于未运行的状态,则需要先调用 onCreate() 然后再调

用 onStart() 的顺序来启动;如果 Service 已经处于运行状态,则只需要调用onStart() 来启动 Service 即可。如果是使用这种方式启动 Service ,那么关闭Service 的方法就很简单,可以通过调用 stopService() 方法停止 Service ,再调用 onDestroy() 方法销毁 Service 。

这种调用方式的 Service 生命周期: onCreate()—>onStart() (多次)— >onDestroy() 。

什么是 Service

2. 使用 Context.bindService() 启动Service

步骤如下:Context.bindService()—>onCreate()—>onBind()—>Service running—>stopService()—>onUnbind()—>onDestroy()—>Service stop 。

onBind 将返回给客户端一个 IBind 接口实例,这个实例允许客户端回调服务方法,比如得到 Service 的运行状态的操作。这种方法会把调用者( Context , Activity 等)和 Service 绑定在一起, Context 退出时, Service 也会调用 onUnbind()—>onDestroy() 退出。所以这种调用方式下 Service 的生命周期为: onCreate()—>onBind() (与第一种方式不同,这里 onBind() 只能绑定一次,不可多次绑定)— >onUnbind()—>onDestroy() 。

跨进程调用

为了解决进程间数据共享的问题,需要把对象拆分成操作系统能理解的简单形式,以便伪装成本地对象进行跨界访问,为此就需要跨进程通信的双方约定一个统一的接口。由于编写这种接口的方法具有很大的共性, Android 提供了 AIDL 工具来辅助完成接口的编写工作。

AIDL(Android Interface Definition Language ,即 Android 接口描述语言 ) 属于 IDL 语言的一种,借助它可以快速地生成接口代码,使得在同一个 Android 设备上运行的两个进程之间可以通过内部通信进程进行交互。

跨进程调用

服务端需要以 aidl 文件的方式提供服务接口, AIDL 工具将生成一个对应的 java 接口对象,并且在生成的接口中包含一个供客户端调用的 stub 服务桩类, Stub 对象就是远程对象的本地代理。服务端的实现类需要提供返回 stub 服务桩类对象的方法。

Service 实例——音乐播放器

可以分别通过 Context.startService() 和Context.bindService() 两种方式来启动 Service 。

示例项目名称为 ServiceDemo 。程序的主界面由ServiceDemo.java 实现,对应的布局文件是 main.xml ,主要实现了通过四个按钮分别启动四种不同的音乐播放方式播放音乐文件,即通过四个 Button 来启动四个不同的 Activity 。

Service 实例——音乐播放器

程序运行效果

初始界面

Service 实例——音乐播放器

public class ServiceDemo extends Activity implements OnClickListener {private Button musicServiceBtn,bindMusicServiceBtn,

receivermusicServiceBtn,remoteMusicServiceBtn; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); findView();

bindButton(); } private void findView() {//用于获取 UI控件的代码集合

musicServiceBtn = (Button) findViewById(R.id.musicService);……//另外三行相似代码略

} private void bindButton() {//用于绑定点击事件监听器的代码集合

musicServiceBtn.setOnClickListener(this);//另外三行相似代码略

}public void onClick(View v) {//点击事件响应处理方法

switch (v.getId()) {case R.id.musicService:

startActivity(new Intent(this, PlayMusic.class));break;

//另外 9行相似代码略}

}}

代码如下:

Service 实例——音乐播放器

启动服务的方式 使用 startService 启动服务 使用 receiver 方式启动服务 使用 bindService 方式启动服务 通过 aidl 方式使用远程服务

用 stopService 方法停止播放音乐

Service 实例——音乐播放器

1. 使用 startService 启动服务

用 startService 方法开始播放音乐

需要构造一个 Intent用于启动 Service,代码如下:Intent intent = new Intent("com.android.ServiceDemo.musicService");

其中 "com.android.ServiceDemo.musicService" 是在 AndroidManifest.xml 文件中对该 service类的唯一指定 name,正因为如此才可以通过该方法启动 service。

<service android:enabled="true" android:name=".MusicService"><intent-filter> <action

android:name="com.android.ServiceDemo.musicService"/></intent-filter>

</service>

然后把各种点击事件所对应的操作码存放到 Bundle(一种数据结构)中再将该数据捆绑到intent上,代码如下:

Bundle bundle = new Bundle();bundle.putInt("op", op);intent.putExtras(bundle);

最后使用 startService(intent)启动服务,服务启动时可以从 intent中取出前面捆绑的 bundle数据结构,从中获取操作码从而获知用户操作的事件。

Service 实例——音乐播放器

2. 使用 receiver 方式启动服务

MusicReceiver 的实现代码如下:

public class MusicReceiver extends BroadcastReceiver {@Overridepublic void onReceive(Context context, Intent intent) {

Intent it = new Intent("com.android.ServiceDemo.musicService");

Bundle bundle = intent.getExtras();it.putExtras(bundle);//构建新的 intent用于启动 MusicServiceif(bundle != null){

int op = bundle.getInt("op");if(op == 4){//判断是否为停止服务操作

context.stopService(it);//在 receiver中停止服务

}else{context.startService(it);//其余操作仍交给

MusicService处理}

}}

}

Service 实例——音乐播放器

3. 使用 bindService 方式启动服务

public class BindMusicService extends Service {private MediaPlayer mediaPlayer;private final IBinder binder = new MyBinder();public class MyBinder extends Binder {//定义自己的 Binder类用于传递

Service对象BindMusicService getService() {

return BindMusicService.this;}

}@Overridepublic IBinder onBind(Intent intent) {//当服务被绑定时返回一个 IBinder对

象, IBinder用于传递 Service对象return binder;

}@Overridepublic void onCreate() {

super.onCreate();Toast.makeText(this, "绑定音乐播放器成功 ",

Toast.LENGTH_SHORT).show();if (mediaPlayer == null) {

mediaPlayer = MediaPlayer.create(this, R.raw.tmp);mediaPlayer.setLooping(false);

}}

@Overridepublic void onDestroy() {

super.onDestroy();Toast.makeText(this, "停止音乐播放器 ",

Toast.LENGTH_SHORT).show();if(mediaPlayer != null){

mediaPlayer.stop();mediaPlayer.release();

}}public void play() {//播放方法,用 public声明供外部使用

if ((!mediaPlayer.isPlaying()) && mediaPlayer != null) {mediaPlayer.start();

}}public void pause() {//暂停方法

if (mediaPlayer != null && mediaPlayer.isPlaying()) {mediaPlayer.pause();

}}public void stop() {//停止方法

if (mediaPlayer != null) {mediaPlayer.pause();mediaPlayer.seekTo(0);

}}

}

Service 实例——音乐播放器

3. 使用 bindService 方式启动服务

Service 实例——音乐播放器

4. 通过 aidl 方式使用远程服务

为了实现通过 aidl 方式使用远程服务,首先需要使用 aidl 编写用于使用远程服务的接口,编写接口的方法是在项目的包构下建立后缀名为 .aidl的文件。

本项目的 IMusicControlService.aidl 文件内容如下:

package org.allin.android.remote;interface IMusicControlService{ void play(); void stop(); void pause();}

Service 实例——音乐播放器

4. 通过 aidl 方式使用远程服务

如何在另外一个应用程序中通过 aidl 接口来调用服务呢?

首先需要将 aidl 接口定义文件IMusicControlService.aidl 包括其包结构复制到 ServiceDemo 下(如下图), ADT 也会在项目中自动生成对应的 Java 接口代码;

然后就可以通过类似于绑定本地服务的方式来绑定该远程服务了。

本章小结

本章介绍了使用 Service最通用的一些用法,包括启动、停止以及关闭服务,但 Service 的还有很多更丰富的使用方法,限于篇幅本书就不进行介绍了,有兴趣的读者可以查阅相关资料,并在实际运用中加以深入学习。

THE END