赵工的个人空间


专业技术部分转网页计算转业余爱好部分


 手持终端

首页 > 专业技术 > 手持终端 > Android系统的Service
Android系统的Service

按照工作方式,Android应用程序可以分为前台和后台两种,Activity是前台应用程序,而Service是后台服务,可使用startService()方法将指定的应用转到后台。
Service分为本地服务Local Service和远程服务Remote Service两种,本地服务主要在应用程序内部使用,应用实现应用程序本身的任务,如自动下载;远程服务主要在应用程序之间使用,如天气预报。
后台服务往往需要运行较长的时间,甚至会从系统启动开始运行到系统关闭。Service一般不与用户交互,并且Service运行时不会获取控制权。Service有自己的声明周期,可以调用Context.startService()来启动一个服务,启动后会一直运行,直到使用Context.stopService()或stopSelf()方法结束服务。
综上所述,Service的特点是:没有用户界面、不与用户交互,长时间运行,不占据程序控制权,优先级比Activity高,不会轻易被Android系统终止。
Android提供了一些特殊的Service类,如AbstractInputMethodService、AccessibilityService、IntentService、RecognitionService、WallpaperService。

1. 创建Service类:

创建一个自定义的Service类,需要继承android.app.Service类,并且重写其onCreate()、onStart()、onDestroy()等方法。其中,onCreate()方法用来初始化Service,是Service生命周期的开始;onStart()用来启动一个Service,表示Service进入运行状态;onDestroy()用来释放Service占用的资源,是Service生命周期的结束。
要使用自定义的Service类,需要在AndroidManifest.xml配置文件进行如下配置:
<service android:name=".MyService" android:enabled="true">
    <intent-filter>
        <action android:name="cn.example.dwenzhao.MY_SERVICE"/>
    </intent-filter>
</service>

2. Service的使用:

Service类创建后,可以通过两种方式启动,Context.startService()或Context.bindService()。
1)Context.startService()启动流程:
context.startService()--onCreate()--onStart()--Service running--context.stopService()--onDestroy() --Service stop
如果Service还没有运行,则Android先调用onCreate()方法,然后调用onStart()方法;如果Service已经运行,则只调用onStart()方法。一个Service的onStart()方法可能会调用多次。
在调用stopService()方法时会直接调用onDestroy()方法,如果是调用者自己直接退出而没有调用stopService(),Service会一直在后台运行。
调用startService方法的生命周期为:onCreate()--onStart()(可多次调用)--onDestroy()
使用startService()启动的服务,要通过调用Context.stopService()或Service.stopSelf()方法来停止,其中stopService()会强制终止当前服务,而stopSelf()直到Intent处理完才停止服务。
2)Context.bindService()启动流程:
context.bindService()--onCreate()--onBind()--Service running--onUnbind()--onDestroy()--Service stop
onBind()将返回给客户端一个IBind接口实例,IBind允许客户端回调服务的方法,如得到Service的运行状态等,这时会把调用者(Context)和Service绑定在一起,Context退出了,Service就会调用onUnbind()--onDestroy()方法相应地退出。同一个Service可以绑定多个服务连接,因而通过绑定方式可以同时为多个不同的应用提供服务。
Context.bindService()绑定一个Service时需要3个参数,第1个参数是Intent对象,第2个参数是服务连接对象ServiceConnection;第3个参数是创建Service的方式,一般指定为自动创建Service.BIND_AUTO_CREATE。其中的服务连接对象ServiceConnection需要创建,要实现其onServiceConnected()和onServiceDisconnected()方法,用于判断连接成功或失败:
ServiceConnection conn=new ServiceConnection(){
@Override
public void onServiceConnected(ComponentName name,IBinder service){
Log.i("SERVICE","连接成功");
}
@Override
public void onServiceDisconnected(ComponentName name){
Log.i("SERVICE","断开连接");
}
};
而绑定Service的代码为:
Context.bindService(intent,conn,Service.BIND_AUTO_CREATE);
调用bindService方法的生命周期为:onCreate()--onBind()(只一次)--onUnbind()--onDestroy()
使用bindService()绑定的服务,要通过Context.unbindService()解除绑定。
startService()和bindService()方式可以混合使用,比如MP3播放器启动音乐功能可通过startService()来播放音乐;对暂停音乐可通过onBind()获取服务连接和Service对象,通过调用该Service对象来暂停。这时,调用stopService()并不能停止音乐Service,需要在所有服务连接关闭后才能停止。

3. Android系统服务:

Android提供了大量系统服务,用于完成不同的功能:

Service名

作用

返回对象

WINDOW_SERVICE

窗口服务

android.view.WindowManager

LAYOUT_INFLATER_SERVICE

布局映射服务

android.view.LayoutInflater

ACTIVITY_SERVICE

活动服务

android.app.ActivityManager

NOTIFICATION_SERVICE

通知服务

android.app.NotificationManager

KEYGUARD_SERVICE

键盘锁服务

android.app.KeyguardManager

LOCATION_SERVICE

位置服务

android.location.LocationManager

SEARCH_SERVICE

本地查询服务

android.app.SearchManager

VEBRATOR_SERVICE

手机震动服务

android.os.Vibrator

CONNECTIVITY_SERVICE

网络连接服务

android.net.ConnectivityManager

WIFI_SERVICE

无线局域网服务

android.net.wifi.WifiManager

TELEPHONY_SERVICE

电话服务

android.telephony.TelephonyManager

SENSOR_SERVICE

传感器服务

android.os.storage.StorageManager

INPUT_METHOD_SERVICE

输入法服务

android.view.inputmethod.InputMethodManager

这些系统服务可以通过Context.getSystemService()方法获取Android系统所支持的服务管理对象,示例:
ActivityManager am=(ActivityManager)getSystemService(ACTIVITY_SERVICE);

4. Notification在状态栏的使用:

NotificationManager类是系统的通知服务管理器,能够将通知信息显示在状态栏上。Notification类用于定义通知的显示(图片及标题等)以及处理通知的应用,其本身并不能实现在状态栏上显示通知的功能,必须通过NotificationManager才能将Notification所定义的通知显示在手机中。具体步骤为:
⑴通过getSystemService(NOTIFICATION_SERVICE)创建NotificationManager对象,用于管理Notification。
⑵使用Notification构造函数创建Notification对象。
Notification notification=new Notification(drawable,ticketText,System.currentTimeMillis());
也可以通过属性设置来设置状态栏上的图标、内容以及显示的时间等。示例:
notification.icon=drawable;
notification.ticketText=tickertext;
notification.when=System.currentTimeMillis();
Notification还提供了声音、震动模式等其他属性:

属性名

描述

andioStreamType

Notification所用的音频流类型

contentIntent

设置单击通知条目时所执行的Intent

contentView

设置在状态栏上显示通知时所显示的视图

defaults

设置默认值,如DEFAULT_LIGHTS默认灯、DEFAULT_SOUND默认声音、DEFAULT_VIBRATE默认震动、DEFAULT_ALL以上默认

deleteIntent

删除所有通知时被执行的Intent

icon

设置状态栏上显示的图标

iconLevel

设置显示图标级别

ledARGB

设置LED颜色

ledOffMS

设置关闭LED时的闪烁时间

ledOnMS

设置开启LED时的闪烁时间

sound

设置一个音频文件作为Notification,其值为一个URI

tickerText

设置状态栏上显示的消息内容

vibrate

设置Notification的震动模式,通常是一个时间数组long[] vibrate=new long[]{1000,1000,1000,1000,1000},。配置文件中需要设置权限

when

通知发生的时间

注:ledOffMS为0而ledOnMS为1表示打开LED,两者设置为0表示关闭LED。
⑶创建Intent对象,并指定其对应的Notification。
Intent intent=new Intent(notification,class);
⑷根据创建的Intent对象创建PendingIntent对象,用于对Intent对象的进一步封装。
PendingIntent mPendingIntent=PendingIntent.getActivity(NotificationName.this,0,intent,0);
⑸调用NotificationManager的notify()方法将通知发送到状态栏中。
nm.notify(R.layout.main,notification);
⑹使用NotificationManager的cancel()方法删除Notification。
nm.cancel(R.layout.main);

5.跨进程服务:

AIDL是Android Interface Definition Language的缩写,用于生成可以在Android设备上两个进程之间进行的通信(IPC,Interprocess Communication)的代码。如果在一个进程中要调用另一个进程中对象的操作,就可以使用AIDL生成可序列化的参数。AIDL IPC机制是面向接口的,,使用代理类在客户端和实现端之间传递数据。
在Android中,每个应用程序都有自己的进程,但Java是不支持跨进行内存共享的,要传递对象需要把对象解析成操作系统能够理解的数据格式,以达到跨界访问对象的目的。由于进程之间的通信信息需要双向转换,所以Android代理类在背后实现了信息的双向转换。只有用户为了进程间的通信允许客户端从不同的应用程序访问Service,以及实现在用户的Service中处理多线程情况下,使用AIPL才是必要的。
1)服务端:
AIDL是一种接口定义语言,编译器通过*.aidl文件的描述信息生成符合通信协议的Java代码,无须自己去写这段代码,只要在需要时调用即可。
首先要建立一个服务端工程,AIDLService,在IPerson.aidl中定义一个hello方法:
package com.mialab.aidl;
interface IPerson{String hello(String someone);}
在Eclipse插件的帮助下,编译器会自动在gen目录中生成对应的IPerson.java文件。
IPerson接口中的抽象内部类Stub继承android.os.Binder类并实现IPerson接口,其中比较重要的方法是asInterface(IBinder)方法,该方法会将IBinder类型的对象转换成IPerson类型,必要时生成一个代理对象返回结果。
接下来就是实现AIDLService,主要代码为:
public class AIDLService extends Service{
private static final String TAG="AIDLService";
IPerson.Stub stub=new IPerson.Stub(){
@Override
public String hello(String someone) throws RemoteException{
Log.d(TAG,"hello() called");
return "Hello,"+someone;
}
};
@Override
public IBinder onBind(Intent intent){
Log.d(TAG,"onBind() called");
return stub;
}
@Override
public boolean onUnbind(Intent intent){
Log.d(TAG,"onUnbind() called");
return true;
}
@Override
public boolean onDestroy(){
super.onDestroy();
Log.d(TAG,"onDestroy() called");
}
}
以上实现了IPerson.Stub抽象类的hello方法,然后在onBind方法中返回stub实例,这样调用方获取的IPerson.Stub就是这个实例,hello方法就会按照期望的那样执行。
要让Service生效,还需要AndroidManifest.xml中对Service进行配置:
<service android:name="cn.example.dwenzhao.service.AIDLService">
    <intent-filter>
        <action android:name="android.intent.action.AIDLService"/>
<category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</service>
2)客户端:
创建客户端工程,如AIDLService_Client,并将IPerson.aidl文件复制到相应目录中,编译器同样生成对应的IPerson.java文件,这样服务端和客户端在通信协议上达到统一,主要工作在MainActivity中完成。
代码中,需要重写ServiceConnection中的onServiceConnected方法,将IBinder类型的对象转换成IPerson类型;再通过服务端Service定义的android.intent.action.AIDLService标识来绑定所需要的服务,这样客户端和服务端就实现了通信的连接。
要把AIDLService.apk通过adb install命令安装到手机模拟器,安装成功后就会在Apps管理界面看到AIDLService。

Copyright@dwenzhao.cn All Rights Reserved   备案号:粤ICP备15026949号
联系邮箱:dwenzhao@163.com  QQ:1608288659