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绑定的服务
5.startService的生命周期3. 服务进程:拥有一个通过startService方法启动的服务的进程
4. 后台进程:拥有一个后台activity(onStop方法被调用)的进程
5. 空进程:没有拥有任何活动的应用组件的进程,也就是没有任何服务和activity在运行
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(); } } }
本文详细介绍了Android中的Service组件,包括Service的基本概念、启动方式、生命周期、进程优先级及远程服务等高级特性。通过实例展示了绑定服务与非绑定服务的区别,以及如何实现混合绑定和远程服务。

被折叠的 条评论
为什么被折叠?



