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

本文详细介绍了Android中的Service组件,包括Service的基本概念、启动方式、生命周期、进程优先级及远程服务等高级特性。通过实例展示了绑定服务与非绑定服务的区别,以及如何实现混合绑定和远程服务。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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.服务进程优先级
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值