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

5.Android基础:四大组件之----->Service

2016-09-18 16:29 946 查看
1.Service运行于后台,没有前台界面的组件,用于运行需要在后台运行的代码


2.可以理解为没有前台的Activity



3.定义方式:创建java类继承Service,清单文件中注册该类

4.服务进程优先级



1. 前台进程:拥有一个正在与用户交互的activity(onResume方法被调用)的进程

1. 拥有一个正在与用户交互的Activity(onResume方法调用)

2. 拥有一个与正在和用户交互的ACtivity绑定的服务

 

3. 拥有一个运行在前台的服务(服务调用了startForeground())
    

4. 拥有一个正在执行其中一个生命周期方法(onCreate(),onStart(),onDestroy())的服务
    

5. 拥有一个正在执行onReceive方法的广播接收者

2. 可见进:拥有一个非前台,但是对用户可见的activity(onPause方法被调用)的进程

1. 拥有一个不在前台但是对用户依然可见的Activity(onPause方法调用)
    

2. 拥有一个与可见Activity绑定的服务

3. 服务进程:拥有一个通过startService方法启动的服务的进程
4. 后台进程:拥有一个后台activity(onStop方法被调用)的进程
5. 空进程:没有拥有任何活动的应用组件的进程,也就是没有任何服务和activity在运行

5.startService的生命周期

1. onCreate->onStartCommand->onDestroy
2.重复的startService不会调用onCreate只会重复调用onStartCommand

下面简单举个例子

配置清单文件

<service android:name="com.runservice.MyService"></service>布局文件
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动服务"
android:onClick="start"
/>

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="停止服务"
android:onClick="stop"
/>

</LinearLayout>测试类

public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

public void start(View v) {
//启动服务
Intent intent= new Intent(this, MyService.class);
startService(intent);
}

public void stop(View v) {
//停止服务
Intent intent= new Intent(this, MyService.class);
stopService(intent);
}
}

6.两种启动服务方式

第一种:绑定启动方式

 bindService

* 绑定服务不会使进程变成服务进程
* 绑定服务,是activity与服务建立连接,如果activity销毁了,服务也会被解绑并销毁,
但是如果服务被销毁,activity不会被销毁

* 绑定服务和解绑服务的生命周期方法:onCreate->onBind->onUnbind->onDestroy

下面举一个小例子

注意:为了解决能够访问服务类中的方法,把需要调用的方法实现接口

配置清单文件

<service android:name="com.leaderservice.LeaderService"></service>
布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击调用"
android:onClick="click"/>

</RelativeLayout>

服务类:

public class LeaderService extends Service {

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
//返回中间对象
return new FengMiShu();
}

class FengMiShu extends Binder implements PublicBusiness {
@Override
//中间进行牵线,连接服务
public void qianXian() {
//调用服务功能
banzheng();
}

public void takeSoap() {

}
}

//通过中间,实现启动自定义服务
public void banzheng() {
System.out.println("成功调用");
}
}
接口类:需要调用的方法实现接口

public interface PublicBusiness {
void qianXian();
}
测试类
public class MainActivity extends Activity {

// private FengMiShu fms;
PublicBusiness pb;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//创建服务意图
Intent intent = new Intent(this, LeaderService.class);
//绑定服务
bindService(intent, new ServiceConnection() {

//到服务的连接建立了,此方法调用(service:这个对象就是onBind返回的中间对象:fengMiShu)
@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

}

}, BIND_AUTO_CREATE);
}

public void click(View v) {
pb.qianXian();
}
}

第二种:非绑定启动方式

 startService

    * 开始服务,会使进程变成为服务进程

    * 启动服务的activity和服务不再有关系
下面举一个小例子

配置清单文件

<service android:name="com.recorder.RecorderService"></service>布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启动电话录音机"
android:onClick="click"/>

</RelativeLayout>服务类
public class RecorderService extends Service {

private MediaRecorder recorder;
@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return null;
}

@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
//获取电话管理器
TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
//监听电话状态
tm.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);
}

class MyListener extends PhoneStateListener {

//电话状态改变时回调
@Override
public void onCallStateChanged(int state, String incomingNumber) {
// TODO Auto-generated method stub
super.onCallStateChanged(state, incomingNumber);
//判断当前是什么状态
switch (state) {
case TelephonyManager.CALL_STATE_IDLE:
// System.out.println("空闲");
if(recorder != null) {
//停止录音
recorder.stop();
//释放录音机占用的资源
recorder.release();
recorder = null;
}
break;
case TelephonyManager.CALL_STATE_RINGING:
// System.out.println("响铃");
if(recorder == null) {
//创建录音对象
recorder = new MediaRecorder();
//设置录音来源
recorder.setAudioSource(MediaRecorder.AudioSource.MIC);
//设置输出录音格式为3GP
recorder.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);
//录制音频路径和名字
recorder.setOutputFile("sdcard/voice.3gp");
//设置音频编码
recorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
try {
//准备录音
recorder.prepare();
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
System.out.println("摘机");
if(recorder != null) {
//开始录音
recorder.start();
}
break;
}
}
}
}

测试类
public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

//启动服务
public void click(View v) {
Intent intent = new Intent(this, RecorderService.class);
startService(intent);
}
}


8.混合绑定

场景使用:音乐播放器

用服务实现音乐播放时,因为音乐播放必须运行在服务进程中,使用非绑定启动方式

但是音乐服务中的方法,需要被前台Activity所调用,又需要实现接口方法,使用绑定启动方式

这时就需要混合启动音乐服务,才能满足。

下面举个简单例子

配置清单文件

<service android:name="com.musicplayer.MusicService"></service>服务类
public class MusicService extends Service {

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
//返回调用里面的方法内容
return new MusicConntroller();
}

//控制音乐,调用服务方法
class MusicConntroller extends Binder implements ControllerInterface {

@Override
public void play() {
// TODO Auto-generated method stub
MusicService.this.play();
}

@Override
public void pause() {
// TODO Auto-generated method stub
MusicService.this.pause();
}

}

public void play() {
System.out.println("开始播放音乐");
}

public void pause() {
System.out.println("暂停播放音乐");
}
}接口类:需要调用的方法实现接口
public interface ControllerInterface {
void play();
void pause();
}

测试类

public class MainActivity extends Activity {

ControllerInterface ci;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

Intent intent = new Intent(this, MusicService.class);
//开始服务,防止返回被自动解绑服务,音乐暂停(把进程变成服务进程)
startService(intent);
//绑定服务(获取中间对象)
bindService(intent, new ServiceConnection() {

//到服务的连接建立了,此方法调用
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
ci = (ControllerInterface) service;
}

//到服务的连接中断了,此方法调用
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub

}

}, BIND_AUTO_CREATE);
}

public void play(View v) {
ci.play();
}

public void pause(View v) {
ci.pause();
}
}

9.远程服务

1.远程服务只能隐式启动,类似隐式启动Activity,在清单文件中配置Service标签时,

必须配置intent-filter子节点,并指定action子节点

2.在启动服务中,可能会出现异常,是因为BinderProxy对象不能转成PublicBusiness,

他们两个不是同一个类,不是父子类关系

解决方法:(里面涉及到进程间的通讯)

Android interfacedefinition language


作用:跨进程通信
应用场景:远程服务中的中间人对象,其他应用是拿不到的,那么在通过绑定服务获取中间人对象时,
就无法强制转换,使用aidl,就可以在其他应用中拿到中间人类所实现的接口

步骤:

1.把绑定启动方式中接口文件的后缀名改成aidl
2. aidl文件中所有东西都是public的,不需要也不能自己定义访问修饰符
3. 中间人对象继承Stub,这个对象已经继承了Binder并实现了PublicBusiness接口
4.. 把远程服务项目的aidl文件复制到启动服务项目中,然后aidl所在的包名06和05项目必须一致
5. 把启动服务项目获取到的中间人对象使用Stub.asInterface强转
下面举个简单的例子
远程服务项目

配置文件
<service android:name="com.paybaby.PayService">
<intent-filter >
<action android:name="com.babypay"/>
</intent-filter>
</service>布局文件
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hello_world" />

</RelativeLayout>

服务类

public class PayService extends Service {

@Override
public IBinder onBind(Intent intent) {
// TODO Auto-generated method stub
return new PayController();
}

class PayController extends Stub {

@Override
public void pay() throws RemoteException {
// TODO Auto-generated method stub
PayService.this.pay();
}

}

private void pay() {
// TODO Auto-generated method stub
System.out.println("检查支付环境");
System.out.println("加密账号密码");
System.out.println("上传账号密码");
System.out.println("完成支付");
}

}
aidl文件

注意文件后缀名是aidl,比如当前文件名为PayInterFace.aidl

package com.paybaby;

interface PayInterFace {
void pay();
}
测试类
public class MainActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}

}
启动服务项目
布局文件

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点我付费"
android:onClick="click"/>

</RelativeLayout>
adil文件

注意:这个文件直接从远程服务项目中,在项目中新建一个包,包名要与所在远程服务中adil文件包名一样

package com.paybaby;

interface PayInterFace {
void pay();
}
测试类
public class MainActivity extends Activity {

PayInterFace pi;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);

//绑定远程服务
Intent intent = new Intent("com.babypay");
bindService(intent, new ServiceConnection() {

//服务中断连接
@Override
public void onServiceDisconnected(ComponentName name) {
// TODO Auto-generated method stub

}

//服务建立连接
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// TODO Auto-generated method stub
//拿到中间人,进行进程通讯 (使用Stub中方法强转)
pi = Stub.asInterface(service);
}
}, BIND_AUTO_CREATE);
}

public void click(View v) {
try {
pi.pay();
} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}


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