Android课堂笔记(七)——服务、广播接收器

目录

一.服务(Service)

1.使用服务

2.服务的形式

3.startService() 的生命周期

4.bindService() 的生命周期

5.启动服务Example

6.绑定服务Example

二.广播接收器(Broadcast Receiver)

1.广播接收器简介

2.创建广播接收器

3.注册广播接收器

4.静态注册广播接收器-无序广播

5.静态注册广播接收器-有序广播

6.动态注册广播接收器


一.服务(Service)

1.使用服务

  • 服务(Service): 后台长时间运行,没有用户界面,是四大应用组件之一
  • 服务在主线程中执行,也可以在主线程外线程中执行,可以从应用组件(例如活动)进行管理
  • 若服务操作耗时,那么最好在服务里单独启动一个线程执行该操作,如下载或更新
  • 服务用于更新数据源,向可见活动提供更新,还可以用于触发通知(SMS或电子邮件的接收的通知)
  • 服务可以从其他组件启动/停止/控制(如活动、其他服务或广播接收器),很多时候从 活动 启动服务

2.服务的形式

  • 服务的形式有很多种,常见的:启动、绑定、IntentService(了解即可)
  • 启动:应用组件(如活动)通过调用 startService() 方法 启动服务
  • 特点:一旦被启动,可以在后台无限期运行,即使启动它的组件已被销毁 
  • 绑定:应用组件(如活动)通过调用 bindService() 方法 绑定到服务上
  • 已绑定的服务提供 客户机-服务器接口,允许应用组件与服务交互、发送请求、获取结果,进行进程间通信(IPC)
  • 特点:多个组件可以同时绑定一个服务,当所有组件解除绑定后,服务被销毁
  • 启动和绑定的区别:启动只能调用服务,绑定可以调用服务,并进行交互

3.startService() 的生命周期

  • 启动服务的生命周期:
  • 当组件(如活动)调用 startService() 方法,将创建服务,该方法用 Intent对象 作为参数
  • 服务正在运行,就调用 onStartCommand() 方法:将其传递给 Intent对象(绑定则是 PendingIntent对象
  • 服务没在运行,则先调用 onCreate() 方法,再调用 onStartCommand() 方法
  • 一旦服务被调用,它将无限期运行,直至:
  1. 服务通过调用 stopSelf() 方法 自行停止
  2. 其他组件通过调用 stopService(Intent iSrvce) 方法停止服务
  • 服务被停止后,系统销毁服务,onDestroy()
  • onStartCommand() 方法 调用多次,onCreate() 方法、onDestroy() 方法 调用一次
  • 注册服务:在 AndroidManifest.xml文件中声明,将 <service>添加为 <application> 的子元素

4.bindService() 的生命周期

  • 绑定服务的生命周期:
  • 当组件(如活动)调用 bindService() 方法,将创建绑定服务
  • 一旦组件与服务绑定,将通过 IBinder接口 与服务通信,就是说可以进行交互
  • 组件可通过调用 unbindService() 方法 来解除绑定
  • 当绑定到服务上的所有组件解除绑定后,该服务将自动停止并销毁
  • 以下哪个方法 不是 创建绑定服务时 实现的?
  • onStartCommand() onCreate() onDestroy() onBind()
  • 当需要将服务和组件绑定时,或者进行跨进程通信时,使用绑定服务

5.启动服务Example

  • MainActivity.java:调用服务
public class MainActivity extends Activity {
        // ...
        // 启动服务 直接把自定义服务写成.class
        intent = new Intent(MainActivity.this,PlayService.class);
    }   
    class ButtonListener implements OnClickListener{
		@Override
		public void onClick(View v) {
			switch(v.getId()){
			case R.id.start:
				startService(intent); // 调用服务
				break;
			case R.id.stop:
				stopService(intent); // 停止服务
				break;
			}}}}
  • PlayService.java:重写服务的各种方法,到系统配置文件中注册服务,到主活动中调用服务
public class PlayService extends Service {	
	MediaPlayer player;      // 声明音乐播放器类
	static boolean isPlay;   // 定义播放器状态
	@Override // I:必须实现的绑定方法,当其他组件通过 BindService()请求与服务绑定时调用
	public IBinder onBind(Intent arg0) {
		return null;
	}	
	@Override // II:当其他组件调用 unbindService()解除被绑定到服务的所有组件的绑定后调用
	public boolean onUnbind(Intent intent) {
		return super.onUnbind(intent);
	}
	@Override 
	public void onCreate() { // 首次创建服务时调用,仅调用一次
		super.onCreate();
		player = MediaPlayer.create(this, R.raw.music2); // 获取音乐播放器组件 res/raw
	}
	@Override // 其他组件请求调用服务时 调用,可执行多次
	public int onStartCommand(Intent intent, int flags, int startId) {
		if (!player.isPlaying()) {     // 如果不是播放状态
			player.start();            // 播放音乐
			isPlay=player.isPlaying(); // 修改播放器状态		
		}
		return super.onStartCommand(intent, flags, startId);
	}	
	@Override 
	public void onDestroy() { // 销毁服务时调用,仅调用一次
		player.stop();        // 关闭播放器
		if (isPlay) {         // 如果正在播放
			player.release(); // 就先释放资源(类似流中的.close手动释放),也可以等垃圾回收机制
		}
		super.onDestroy();
	}}
  • 音乐播放服务界面展示:

6.绑定服务Example

  • MainActivity.java:调用服务
public class MainActivity extends Activity {	
        // ...
        // 获取 Intent和 MyserviceConnection对象
        intent=new Intent(MainActivity.this,MyService.class);
        con=new MyServiceConnection();
    }    
    class ButtonListener implements OnClickListener{
		@Override
		public void onClick(View v) {
			switch(v.getId()){
			case R.id.bind:
				//三个参数:意图、ServiceConnection对象监视服务连接状态、Flag标记值
                // Flag标记值:用于指定绑定该服务时是否自动创建服务
	            bindService(intent, con, BIND_AUTO_CREATE);
				break;
			case R.id.unbind:
				unbindService(con); 
			    Log.i("bindService","--MainActivity unbindService(con)--");
				break;
			case R.id.getNumber:
			    StringBuffer buffer =new StringBuffer();
			    buffer.append("号码是:");
				List number = myService.getRandomNumber();  // 获取随机数组
                for (int i = 0; i < number.size(); i++) {   //遍历数组并显示
                    buffer.append(number.get(i));
                    buffer.append(",");
                }
                Toast.makeText(MainActivity.this, buffer, Toast.LENGTH_LONG).show();
			    Log.i("bindService","--MainActivity number--");
				break;
			}}}
    private ServiceConnection con = new ServiceConnection() { // 与 后台Service进行通讯
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            // 获取后台Service信息
            myService = ((MyService.MyBinder) service).getService();  
        }
        @Override
        public void onServiceDisconnected(ComponentName name) { // 解除绑定调用
        }};
  • MyService.java:重写服务的各种方法,到系统配置文件中注册服务,到主活动中调用服务
public class MyService extends Service {
	public MyService() {
		super();}
	@Override	
	public void onCreate() {               // 1:首次创建服务时调用,调用一次
		super.onCreate();}
	public class MyBinder extends Binder{  // 2:创建MyBinder内部类 并获取 服务对象 与 Service状态
		public MyService getService(){     // 创建 获取Service的方法
			return MyService.this;         // 返回 当前Service类
			}}	
	@Override
	public IBinder onBind(Intent intent) { // 3:当服务绑定的时候调用该方法
		return new MyBinder();             // 返回 MyBinder服务对象 实现绑定组件和服务间的交互
	}
	 public List getRandomNumber() {       // 创建获取 7个33以内随机号码的方法
	        List resArr = new ArrayList(); // 创建 ArrayList数组
	        String strNumber="";
	        for (int i = 0; i < 7; i++) { 
	            int number = new Random().nextInt(33) + 1;
	            if (number<10) {           // 在数字1~9前加0 数字格式化
	                strNumber = "0" + String.valueOf(number);
	            } else {
	                strNumber=String.valueOf(number);}
	            resArr.add(strNumber);}
	        return resArr;  }
	@Override // 5:当服务 解除完所有绑定的时候 调用该方法
	public boolean onUnbind(Intent intent) {
		return super.onUnbind(intent);
	}	
		@Override // 6:当销毁服务时调用 仅调用一次
		public void onDestroy() {
			super.onDestroy();
		}}
  • 获取随机数字服务界面展示:
  • 日志界面:
  • 解除绑定之后仍可获取随机数字,除非关闭通道ServiceConnection
  • 解除绑定按钮仅能点击一次,否则报错

二.广播接收器(Broadcast Receiver)

1.广播接收器简介

  • 广播接收器:四大组件之一,负责接受和响应广播消息,不提供 UI,可以创建状态栏通知
  • 广播以 intent 的形式 传达
  • 广播可由 系统 / 应用 生成:系统比如电量过低,应用比如求取权限
  • 可以接收的广播类型主要有两种:普通广播、有序广播
  • 普通广播:广播被 同时发送 到所有相关接收器,接收器以未定义顺序(无序)运行    
  • void  sendBroadcast(Intent intent,String receiverPermission);      
  1. intent:要被广播的 intent      
  2. receiverPermission:可选参数,通常省略,指定广播接收器必须有的权限
  • 有序广播:按顺序 将广播发送给接收器,这意味着一次向一个接收器发送广播
  • void  sendOrderBroadcast(Intent intent,String receiverPermission);      

  • android:priority属性:设置接收器接收的先后顺序

2.创建广播接收器

  • 创建广播接收器步骤:
  1. 集成 BroadcastReceiver类,创建其子类,并重写其中的 onReceive() 方法
  2. 注册广播接收器
  • onReceive(Context context, Intent intent) :
  • 广播接收器接收 广播intent 时调用,必须包括在接收广播时需要执行的代码
  1. Context是接收器运行所在的上下文
  2. Intent:是正被接受的intent
  • abortBroadcast() 方法:终止继续传播,若不需要向下个广播接收器传送广播

3.注册广播接收器

  • 注册广播接收器有两种形式:静态注册、动态注册
  • 静态注册: AndroidManifest.xml清单文件 中注册
  • 动态注册: java代码中 注册,该情况下,程序执行到注册的代码后才会注册
  • unregisterReceiver(BroadcastReceiver) 方法:动态注册中,取消注册广播接收器
    IntentFilter filter = new IntentFilter();
    filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
    registerReceiver(myBroadcastReceiver,filter);
  • 常见广播事件:

ACTION_BATTERY_LOW

电量不足

ACTION_HEADSET_PLUG

耳机插入拔出

ACTION_SCREEN_OFF 和 ACTION_SCREEN_ON

屏幕打开关闭,是系统生成的 intent

ACTION_TIMEZONE_CHANGED

时区设置更改

ACTION_BOOT_COMPLETED

设备完成启动

ACTION_CAMERA_BUTTON

启动相机

4.静态注册广播接收器-无序广播

// MainActivity.java:调用广播接收器
public class MainActivity extends Activity {
        // ...
		send.setOnClickListener(new OnClickListener() { 
			@Override
			public void onClick(View v) {
				Intent intent=new Intent(MainActivity.this,MyMessageReceiver.class);
				// intent意图启动组件的同时,可以传送数据
                // 可以打包成一个Bundle传递,也可以直接 以键-值对的形式 放入数据
				intent.putExtra("message",etMsg.getText().toString());
				sendBroadcast(intent); // 发送无序广播
			}});}}
// MyMessageReceiver.java :定义广播
public class MyMessageReceiver extends BroadcastReceiver{ // 定义广播接收器
	@Override 
	public void onReceive(Context context, Intent intent) { // 重写方法,收到广播自动调用
		// 字符串,用getStringExtra()获取,如果是int,则用getIntExtr()获取
		String msg=intent.getStringExtra("message");
		Toast.makeText(context,"收到信息:"+msg, Toast.LENGTH_LONG).show();
	}}
// AndroidMainfest.xml:静态注册广播接收器
<receiver android:name="com.Lyrelion.messagereceiver.MessageReceiver1">
        // intent-filter:设置广播接收器可以接受的Intent
        // priority:接受广播的优先级别,值从-1000到1000,越高,越优先 -->
        <intent-filter android:priority="999">
        <action android:name="andyreceiver"/>
        </intent-filter>
</receiver>

5.静态注册广播接收器-有序广播

// MainActivity.java:调用广播接收器
public class MainActivity extends Activity {
            // ...
			@Override
			public void onClick(View v) {
				Intent intent=new Intent(); 
				// 隐式Intent:不明确指定目标组件的名称,通过action等信息过滤要使用的目标组件
				intent.setAction("andyreceiver"); // 与系统清单文件中保持一致
                sendOrderedBroadcast(intent,null); // 发送有序广播
			}});}}
// MessageReceive1.java:定义广播接收器1
public class MessageReceiver1 extends BroadcastReceiver{
	public void onReceive(Context context, Intent intent) {
		Toast.makeText(context,"Receiver1收到消息!",Toast.LENGTH_SHORT).show();
	}}
// MessageReceive2.java:定义广播接收器2
public class MessageReceiver2 extends BroadcastReceiver{
	public void onReceive(Context context, Intent intent) {
		Toast.makeText(context,"Receiver2收到消息!",Toast.LENGTH_SHORT).show();
		abortBroadcast(); // 终止继续传播	
	}}
// 系统文件清单.xml:设置广播接收顺序
       <receiver android:name="com.aa.messagereceiver.MessageReceiver1">
             <intent-filter android:priority="999">
                 <action android:name="andyreceiver"/> // 与下面保持一致
             </intent-filter>
        </receiver>
        <receiver android:name="com.aa.messagereceiver.MessageReceiver2">
             <intent-filter android:priority="1000"> // 所以先接受广播,1000>999
                 <action android:name="andyreceiver"/> // 与上面保持一致
             </intent-filter>
        </receiver>
  •  先收到2的消息(优先级高),再接收1的消息:

6.动态注册广播接收器

// MainActivity.java
public class MainActivity extends Activity {
        // ...
        mr=new MessageReceiver();               // 实现广播接收器的动态注册    
        IntentFilter filter=new IntentFilter(); // 动态注册广播
        filter.addAction("msgReceiver");
        registerReceiver(mr,filter);
        send.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Intent intent=new Intent(); 
				intent.setAction("msgReceiver");				
				sendBroadcast(intent);      // 发送广播
			}});  
        unregister.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				unregisterReceiver(mr);     // 取消注册广播接收器
			}});}}

// MessageReceiver.java
public class MessageReceiver extends BroadcastReceiver{
	public void onReceive(Context context, Intent intent) {
		Toast.makeText(context,"收到消息,over!",Toast.LENGTH_LONG).show();
	}}

// TimeZoneReceiver.java
public class TimeZoneReceiver extends BroadcastReceiver{
	public void onReceive(Context context, Intent intent) {
		Toast.makeText(context,"时区改变了!",Toast.LENGTH_LONG).show();
	}}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Lyrelion

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值