android Service学习笔记

服务简介

Service在继承关系上是Activity的大爷,也就是说Activity多继承了一个类,封装了界面相关,等等其他操作。

服务没有onPause、onStop、onResume、onRestart方法,因为service没有界面,长期运行在后台。

startService方式启动服务

Start方式启动服务声明周期:

服务被创建时依次调用onCreate、onStartCommand;
  同一个服务只能被创建一次(onCreate),再次创建就只会执行onStartCommand;

  一个服务只能被停止一次; 

生命周期的方法:

   onCreate:服务被创建的时候调用这个方法;
onStartCommand :开启服务

   onDestroy:销毁服务

Start方式服务的创建步骤

1. 自定义服务类继承Service,并实现相关函数
2. 在配置文件中声明服务
3. 启动服务(startService,后面讲解bindService)

bindService方式启动服务

bind方式开启服务的生命周期

    bindService绑定服务、unBindService解除绑定的服务;
服务是在被绑定的时候被创建,调用oncreate、onbind方法;
    服务只能被绑定一次;
服务只能被解除绑定一次,解除绑定的时候调用onUnbind、onDestrory方法,如果多次解除绑定会抛出异常;
    
    推荐的方式:

    startService:开启并创建一个服务,服务长期运行在后台;
    bindService:绑定服务,可以调用服务里面的方法;
    unBindService:解除服务,停止服务里面的方法;
    stopService:停止服务,销毁服务对象;

为什么要引入bindservice的API

1.服务启动后有时候会需要调用服务里面的方法,这就需要bindService来绑定服务
2.为了调用服务中的业务逻辑方法。

绑定服务调用服务方法的过程

    通过bindservice方式实现调用服务里面业务逻辑方法:
    步骤:
1、在服务类中创建一个中间人MyBinder类,继承了Binder,Binder实现了IBinder接口:
    	public class MyBinder extends Binder{
		}
2、在服务类里面创建了一个MyBinder的成员变量:
private MyBinder myBinder;
    3、在MyBinder类中写一个方法用于调用服务的业务逻辑方法:
		public class MyBinder extends Binder{
		//使用中间人调用服务里的方法
		public void callMethodInService(){
			methodInService();
			}
		
		}
    4、在activity中bindService时,定义了ServiceConnection,用它来监听绑定完成时的函数回调,在这个连接中实现了两个函数:
		private class MyConn implements ServiceConnection {
			/**
			 * 服务连接成功时调用这个方法
			 */
			@Override
			public void onServiceConnected(ComponentName name, IBinder service) {
				//得到服务绑定成功后返回的中间人MyBinder对象
				myBinder = (MyBinder) service;
	
			}
	
			/**
			 * 服务断开成功时调用这个方法
			 */
			@Override
			public void onServiceDisconnected(ComponentName name) {
				System.out.println("-------onServiceDisconnected-------");
	
			}
	
		}
     5、通过在activity中通过中间人条用服务的业务逻辑方法:
myBinder.callMethodInService();

绑定服务抽取接口

    接口(interface): 对外开放暴露的功能,但是不会暴露功能实现的细节;
    让中间人实现服务接口的目的:只对外暴露接口里面业务逻辑方法,隐藏中间人里面的其他方法;
我们上面定义的MyBinder类太开放,如果别人获取了我们的MyBinder类的对象,就可以查看MyBinder类中的所有方法,
这是我们不允许的,我们只想别人看到我们允许别人调用的方法,而不想别人看到MyBinder类中的其他方法。要想实现这个
要求,我们让MyBinder再实现一个接口,接口中只有我们想让别人看到的方法,然后把接口给别人。

步骤:

    1、创建一个服务的接口类,里面包含需要对外暴露的业务逻辑方法:
	public interface IService {
		public void callMethodInService();
	}
    2、让服务中的中间人实现了服务的接口类:
		private class MyBinder extends Binder implements IService{
		
		//(实现服务接口中的方法)使用中间人调用服务里的方法
		public void callMethodInService(){
			methodInService();
		   }
		}
3、在activity中声明接口的成员变量:
private IService myBinder;

    4、强制转换成服务的接口类型
	private class MyConn implements ServiceConnection {


		/**
		 * 服务连接成功时调用这个方法
		 */
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			//强制转换成服务的接口类型
			myBinder = (IService) service;
		}

     5、在activity中通过接口的成员变量调用服务的业务逻辑方法:
public void call(View view){
		myBinder.callMethodInService();
	}

绑定服务的应用场景

     1、需要在后台运行一定的业务逻辑,而且需要与服务器端交互数据,都是写在服务里面的。
     2、天气预报、股票行情软件;
尤其是音乐播放器的播放暂停等,我们希望退出Activity后音乐可以继续播放,这就用到了Service,它可以在后台运行,我们又想在Activity中控制
音乐的播放暂停等功能,这就用到了BindService来调用服务里面的方法。

服务案例

电话窃听器(start方式启动服务)

步骤:

1、在工程中添加一个服务Service,重新onCreate方法;
2、在清单文件中配置服务;
        3、在activity中开启服务;
4、在onCreate方法中使用TelephonyManager监听电话的状态;
5、在清单配置文件中添加权限

示例代码:

1、在工程中添加一个服务Service,重新onCreate方法:
  public class DHQTService extends Service {
				/**
			 * 当服务被创建的时候调用这个方法
			 */
			@Override
			public void onCreate() {
				System.out.println("=========onCreate=========");
				super.onCreate();
		
				TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
		
				tm.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);
		
			}
			}

   2、在清单文件中配置服务:
			<service android:name="com.itheima.dhqtq.DHQTService"></service>

3、在activity中开启服务:

service = new Intent(this,DHQTService.class);
			//开启服务
			startService(service);	

   4、在onCreate方法中使用TelephonyManager监听电话的状态:
			
			/**
			 * 当服务被创建的时候调用这个方法
			 */
			@Override
			public void onCreate() {
				System.out.println("=========onCreate=========");
				super.onCreate();
		<span style="white-space:pre">		</span>//通过获取系统服务得到TelephonyManager,用它来监听电话状态
				TelephonyManager tm = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
		<span style="white-space:pre">		</span>//使用TelephonyManager监听电话状态,并设置监听器
				tm.listen(new MyListener(), PhoneStateListener.LISTEN_CALL_STATE);
		
			}

			/**
			*自定义一个电话状态监听器,监听电话
			*/
			private class mylistener extends phonestatelistener {
	<span style="white-space:pre">		</span>//使用MediaRecorder类录音
			private MediaRecorder r;
	<span style="white-space:pre">		</span>//电话状态改变会调用此函数
			@Override
			public void onCallStateChanged(int state, String incomingNumber) {
	
				try {
					// super.onCallStateChanged(state, incomingNumber);
					System.out.println("====state===============" + state);
					switch (state) {
					case TelephonyManager.CALL_STATE_IDLE:// 闲置状态
						System.out.println("关闭录音机,上传音频文件..................");
						if(r != null){
							r.stop();//录制完成
							r.release();//释放资源
							r = null;
							//上传文件
						}
						break;
	
					case TelephonyManager.CALL_STATE_RINGING:// 来电话状态
						System.out.println("准备好录音机,准备录音..................");
	<span style="white-space:pre">					</span>//创建一个MediaRecorder对象
						r = new MediaRecorder();
	<span style="white-space:pre">					</span>//设置捕获设备为麦克
						r.setAudioSource(MediaRecorder.AudioSource.MIC);
						r.setOutputFormat(MediaRecorder.OutputFormat.THREE_GPP);//设置输出格式为3gp
						//设置输出目录
						//r.setOutputFile("/mnt/sdcard/info.3gp");
						r.setOutputFile(Environment.getExternalStorageDirectory()+"/info.3gp");
						r.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);//设置音频编码格式
						r.prepare(); //准备录制
	
						break;
	
					case TelephonyManager.CALL_STATE_OFFHOOK:// 接听状态
						System.out.println("开始录音..................");
						r.start();//开始录制
						break;
	
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
	
		}

5、在清单配置文件中添加权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
   		<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    	<uses-permission android:name="android.permission.RECORD_AUDIO"/>
    	<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

利用服务注册广播接收者

      操作频繁的广播事件,如果只是在清单配置文件配置,是不生效的。需要使用代码注册才能生效;比如 屏幕解锁开锁
电池电量低了只能通过代码的方式进行注册才会生效。但是如果在Activity中动态注册广播,在Activity销毁时如果没有解除注册广播,Activity会提示
一个错误(Activity漏气(直译)了),所以在Activity销毁时需要解除注册广播,但解除我们就无法收到广播了,
如果你想一直接收操作频繁的广播事件,那就在服务中动态注册广播,而不去解除注册广播。

     步骤:

动态注册广播接收者
// 1、得到广播接收者的对象
		ScreenBroadCastReceiver screenReceiver = new ScreenBroadCastReceiver();
		// 2、创建一个intentFilter对象
		IntentFilter filter = new IntentFilter();
		// 3、注册接收的事件类型
		filter.addAction("android.intent.action.SCREEN_ON");
		filter.addAction("android.intent.action.SCREEN_OFF");
		// 4、注册广播接收者
		this.registerReceiver(screenReceiver, filter);

 远程服务aidl的写法 

service的2个概念  
本地服务  --    运行在当前自己应用的service 
远程服务  ---   运行在其他应用进程里的service
调用远程服务
aidl
---  Android interface definition language  出现目的是为了解决进程间通信
IPC
--- inner process communication

aidl调用远程服务的步骤

//首先开启远程服务支持
1. 把src目录中的接口定义文件Iservice.java的后缀名改为 aidl要把public关键字 去掉,保存后自动在gen目录下生成iservice.java文件
iservice.java中自动生成了Stub类

2.定义的中间人对象MyBinder 继承Stub 
private class Mybinder extends Stub{.....}

//调用远程服务,把远程服务中的aidl文件拷贝过来
3. 要保证2个应用是统一aidl文件  aidl所在保证包名一样

4. 在获取中间人对象的时候直接用Stub类获取即可
 iservice = Stub.asInterface(service);

远程服务的应用场景

1. 支付宝
2. 捕鱼达人  花钱买超级大炮   欢乐斗地主

你可能感兴趣的:(service)