广播BroadcastReceiver(1)

 广播可以理解为是一种通信的模式,即1个发送方,若干个接收方,
     例如: 1个电视台与若干个电视台,1个老师与若干个学生,1个数据发送方与若干个接收方
             在广播的通信模式中,广播表现为两种方式:发送方,接收方
    在广播的通信模式中,接收方的数量是若干个,广播的发送方会在需要发送
    广播的时候即发出广播,并不关心接收方的数量跟状态。
    在Android系统中,使用广播机制可以实现线程之间、组件之间、进程之间的通信,如:
    同一个进程中主线程与子线程之间的通信,使用主线程和子线程中的任何一个作为广播的发送方,而
    其他的线程作为广播的接收方;
    同一个应用程序中Activity与Service之间的通信,使用Activity和Service中的任意一个作为广播的发送方,
    另一个作为广播的接收方;
    使用A应用程序的组件发送广播,而在B应用程序中接收广播;


  从实现原理上看,Android中的广播使用了观察者模式,基于消息的发布/订阅事件模型,一旦广播的接收方完成订阅,
  当广播发出时,接收方即可收到该广播。
  跟收音机接收广播需要一个“频道号”类似,Android系统中的广播机制中也存在类似的概念,它通常表现为
  使用IntentFilter对Intent进行过滤,或声明权限(Permission)进行过滤。
  Android系统本身也大量的使用了广播机制,在许多特定的情境下都会发送特定的广播,
  以使得对应的处理程序可以做出响应,开发人员也可以接收这些广播,以完成一些特定的任务。
      Android系统会发出的广播例子:
            开机完成、屏幕打开/关闭、新的呼出电话、接收到短信等。
   在Android系统中,广播大致区分为:
       普通广播/无需广播:广播的接收者们在接收广播时,没有先后之分,任何一个接收者都有可能是第1个
接收到广播的,也可能是最后1个接收到广播的;
有序广播:广播的接收者们会根据一定的顺序先后接收到广播,且先接收到广播的接收者可以阻止广播继续向其他的接收者发送,也可以向其他的接收者传递数据,或
修改前一个接收者中向后传递的数据;
粘性广播:在Android5.0(API 21)中已经声明为不推荐继续使用(Deprecated)。
在ContextWrapper类中定义了发送广播的方法,常用的有:
    public void sendBroadcast(Intent intent)


    public void sendBroadcast(Intent intent,String receiverPermission)


    public void sendOrderBroadcast(Intent intent,String receiverPermission)


在Android系统中,广播接收者(BroadcastReceiver)是核心系统组件之一,当开发人员需要定义广播接收者时,
则需要自定义类继承BroadcastReceiver类。
广播接收者可以在AndroidMainfest.xml文件对BroadcastReceiver类进行注册,也可以使用ContextWrapper类
中定义的registerReceiver()方法注册,前者被称之为静态注册的方式,而后者被称之为动态注册的方式。
总的来说,广播是一种发送与接受数据的通信机制;
          使用广播可以实现线程间、组件间、进程间的通信;
          BroadcastReceiver是Android系统的核心组件之一,其注册方式可区分为动态注册和静态注册。
          Android系统中的广播区分为普通广播(无序广播)和有序广播;
          开发人员可以自定义BroadcastReceiver接收系统广播,以处理一些特定的业务;
  发送广播与接收广播
      发送广播的方法:
             public void sendBroadcast(Intent intent)
    在一般情况下,广播的发送方与接收方的匹配通过IntentFilter与Intent实现过滤,因此
 发送广播时,Intent中应该携带过滤/匹配时需要的属性,例如Action
当在AndroidMainfest.xml文件中注册BroadcastReceiver时,须在<application>节点下添加
     <receiver>节点以注册BroadcastReceiver,并且在<receiver>节点下配置<intent-filter>,
     以确定接收哪些广播。
    实例:

       布局,在布局中添加一个简单的按钮:

 <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:onClick="doSendBroadcast"
        android:text="发送普通广播" />

MainActivity:

public class MainActivity extends Activity {
	
	
    @Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
    }
    public void doSendBroadcast(View view){
    	Intent intent = new Intent();
    	intent.putExtra("data", "data = " + new Date());
    	intent.setAction("ACTION_TEST_BROADCAST");
    	sendBroadcast(intent);
    	
    }
}

TestBroadcastReceiver:

public class TestBroadcastReceiver extends BroadcastReceiver{

	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		System.out.println(intent.getStringExtra("data"));
		
	}

}

在AndroidMainfest.xml中配置:

<receiver 
            android:name="com.example.lianxi.TestBroadcastReceiver">
            <intent-filter >
                <action android:name="ACTION_TEST_BROADCAST"/>
            </intent-filter>
        </receiver>

动态注册广播接收者:
  当通过ContextWrapper类中定义的registerReceiver()方法注册
  BroadcastReceiver时,需要手动的创建IntentFilter类的对象,作为该方法的参数:
      public Intent registerReceiver(BroadcastReceiver receiver,IntentFilter filter)
  使用动态注册时,应该及时取消注册,例如在Activity的onCreate()方法中注册,
  则在同一个Activity的onDestroy()方法中取消注册,否则会抛出异常,取消注册的方法为:
        public void unregisterReceiver(BroadcastReceiver receiver)
实例,布局与上面一样:

 public class MainActivity extends Activity {
	
	private BroadcastReceiver receiver = new InnerBroadcastReceiver();
	
    @Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		IntentFilter filter = new IntentFilter();
		filter.addAction("ACTION_TEST_BROADCAST");
		registerReceiver(receiver, filter);
		
    }
    
    private class InnerBroadcastReceiver extends BroadcastReceiver{

		@Override
		public void onReceive(Context context, Intent intent) {
			// TODO Auto-generated method stub
			System.out.println( "InnerBroadcastReceiver" + intent.getStringExtra("data"));
		}
    	
    }
    public void doSendBroadcast(View view){
    	Intent intent = new Intent();
    	intent.putExtra("data", "data = " + new Date());
    	intent.setAction("ACTION_TEST_BROADCAST");
    	sendBroadcast(intent);
    	
    }
    //要取消注册,否则的话logcat会报错
    @Override
    protected void onDestroy() {
    	// TODO Auto-generated method stub
    	unregisterReceiver(receiver);
    	super.onDestroy();
    }
}

 静态注册与动态注册BroadcastReceiver的区别通常表现为:
          静态注册的BroadcastReceiver是常驻型,当其所属的应用程序安装到设备中时,
 该BroadcastReceiver即完成注册,无论应用程序是否处于运行状态,都可以正常接收到广播;
 动态注册的BroadcastReceiver仅当调用了registerReceiver()方法后才完成注册,
 且当调用了unregistereReceiver()方法后即停止工作
 在接收有序广播时,动态注册的BroadcastReceiver的优先级高于静态注册的BroadcastReceiver;
 某些广播只有动态注册的BroadcastReceiver才可以接收。
 
  使用广播更新音乐播放
          实例:
     MainActivity:

 package com.example.lianxi;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TextView;

public class MainActivity extends Activity {

	private ImageButton play_Button;
	private ProgressBar progressbar;
	private TextView start_Time, end_Time;
	private BroadcastReceiver receiver;

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

		play_Button = (ImageButton) findViewById(R.id.play);
		progressbar = (ProgressBar) findViewById(R.id.music_seek);
		start_Time = (TextView) findViewById(R.id.start_time);
		end_Time = (TextView) findViewById(R.id.end_time);

		play_Button.setOnClickListener(new InnerOnClickListener());
		startService(new Intent(this, PlayMusicService.class));
	 receiver = new InnerBroadcastReceiver();
	 IntentFilter filter = new IntentFilter();
	 
	 filter.addAction("com.edu.hpu.intent.action.UPDATE_PROGRESS");
	 filter.addAction("com.edu.hpu.SET PAUSE_BUTTON");
	 filter.addAction("com.edu.hpu.SET PLAY_BUTTON");
	 registerReceiver(receiver, filter);
	}

	private class InnerOnClickListener implements View.OnClickListener {

		@Override
		public void onClick(View v) {
			// TODO Auto-generated method stub
           Intent intent = new Intent("com.edu.hpu.intent.action.PLAY_MUSIC");
           sendBroadcast(intent);
			
		}

	}
private class InnerBroadcastReceiver extends BroadcastReceiver{

	@Override
	public void onReceive(Context context, Intent intent) {
		// TODO Auto-generated method stub
		if("com.edu.hpu.SET PAUSE_BUTTON".equals(intent.getAction())){
			play_Button.setImageResource(android.R.drawable.ic_media_pause);
		}else if("com.edu.hpu.SET PLAY_BUTTON".equals(intent.getAction())){
			play_Button.setImageResource(android.R.drawable.ic_media_play);
			
		}
		else if("com.edu.hpu.intent.action.UPDATE_PROGRESS".equals(intent.getAction())){
		int currentPosition = intent.getIntExtra("current_position", 0);
		int duration = intent.getIntExtra("duration", 0);
		int progress = currentPosition * 100 / duration;
		start_Time.setText(getFormattedTime(currentPosition));
		end_Time.setText(getFormattedTime(duration));
		progressbar.setProgress(progress);
		}
	}
	
}
	private String getFormattedTime(long date) {
		return new SimpleDateFormat("mm:ss", Locale.CHINA)
				.format(new Date(date));
	}
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		unregisterReceiver(receiver);
		stopService(new Intent(this,PlayMusicService.class));
		super.onDestroy();
	}
}

PlayMusicService:

package com.example.lianxi;

import java.io.IOException;

import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.media.MediaPlayer;
import android.os.Environment;
import android.os.IBinder;

public class PlayMusicService extends Service {
	private MediaPlayer player;
	private String musicPath;
	private int currentPosition;
	private BroadcastReceiver receiver;
	private boolean isRunning;

	@Override
	public void onCreate() {
		player = new MediaPlayer();
		player.setOnPreparedListener(new InnerPreparedListener());
		musicPath = Environment.getExternalStoragePublicDirectory(
				Environment.DIRECTORY_MUSIC).toString()
				+ "/number1.mp3";
		IntentFilter filter = new IntentFilter();
		filter.addAction("com.edu.hpu.intent.action.PLAY_MUSIC");
		receiver = new InnerBroadcastReceiver();
		registerReceiver(receiver, filter);
		isRunning = true;
		new UpdateProgressThread().start();
	}

	// 子线程发送广播
	private class UpdateProgressThread extends Thread {
		@Override
		public void run() {
			while (isRunning) {

				if (player.isPlaying()) {
					Intent intent = new Intent(
							"com.edu.hpu.intent.action.UPDATE_PROGRESS");
					intent.putExtra("current_position",
							player.getCurrentPosition());
					intent.putExtra("duration", player.getDuration());
					sendBroadcast(intent);
				}
				try {
					Thread.sleep(500);
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
	}

	private class InnerBroadcastReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			Intent it = new Intent();
			if (player.isPlaying()) {
				pause();
				it = new Intent("com.edu.hpu.SET PLAY_BUTTON");
				sendBroadcast(it);
			} else {
				play();
				it = new Intent("com.edu.hpu.SET PAUSE_BUTTON");
				sendBroadcast(it);
			}
		}

	}

	private void play() {

		try {
			player.reset();
			player.setDataSource(musicPath);
			player.prepareAsync();
			// player.start();
		} catch (IllegalArgumentException e) {
			// TODO: handle exception
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void pause() {
		if (player.isPlaying()) {
			currentPosition = player.getCurrentPosition();
			player.pause();
		}
	}

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

	private class InnerPreparedListener implements
			MediaPlayer.OnPreparedListener {

		@Override
		public void onPrepared(MediaPlayer mp) {
			// TODO Auto-generated method stub
			if (currentPosition != 0) {
				mp.seekTo(currentPosition);
			}
			mp.start();
			currentPosition = 0;
		}

	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		player.release();
		player = null;
		isRunning = false;
		unregisterReceiver(receiver);
		super.onDestroy();
	}

}

配置信息:

<service 
            android:name="com.example.lianxi.PlayMusicService"></service>

布局:

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

    <ImageButton
        android:id="@+id/play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="20dp"
        android:src="@android:drawable/ic_media_play" />

    <ProgressBar
        android:id="@+id/music_seek"
        style="?android:attr/progressBarStyleHorizontal"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:max="100"
         />

    <RelativeLayout
        android:layout_width="fill_parent"
        android:layout_height="wrap_content"
        android:gravity="center_horizontal" >

        <TextView
            android:id="@+id/start_time"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginLeft="10dp"
            android:gravity="left"
            android:text="00:00" />

        <TextView
            android:id="@+id/end_time"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginRight="10dp"
            android:gravity="right"
            android:text="00:00" />
    </RelativeLayout>

</LinearLayout>

使用广播监听短信
        当新的短信到来时,系统会发出如下的广播:
    android.provider.Telephony.SMS_RECEIVED
   
           实例:

MainActivity:

 public class MainActivity extends Activity {

	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		
		startService(new Intent(this,SmsReceiverService.class));
	}
	
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		stopService(new Intent(this,SmsReceiverService.class));
		super.onDestroy();
	}
	
}

SmsReceiverService:

 public class SmsReceiverService extends Service{

	private BroadcastReceiver receiver;
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
	    receiver = new InnerBroadcastReceiver();
	    IntentFilter filter = new IntentFilter();
	    filter.addAction("android.provider.Telephony.SMS_RECEIVED");
       registerReceiver(receiver, filter);	    
	}
	
	private class InnerBroadcastReceiver extends BroadcastReceiver{

		@Override
		public void onReceive(Context context, Intent intent) {
			// TODO Auto-generated method stub
			Object[] pdus = (Object[])intent.getExtras().get("pdus");
			
			SmsMessage message;
			byte[] pdu;
			for (int i = 0; i < pdus.length; i++) {
				pdu = (byte[]) pdus[i];
	            message = SmsMessage.createFromPdu(pdu);
	            
	            String body = message.getMessageBody();
	            String address = message.getOriginatingAddress();
	            long time = message.getTimestampMillis();
	           System.out.println(address);
	           System.out.println("信息="+body);
	           System.out.println(new Date(time).toString());
			}
			
		}
		
	}
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}
	@Override
	public void onDestroy() {
        unregisterReceiver(receiver);	
		super.onDestroy();
	}

}

不要忘了注册Service和添加权限,这里不再一一介绍了


posted @   wojiaohuangyu  阅读(6)  评论(0编辑  收藏  举报
编辑推荐:
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
阅读排行:
· 终于写完轮子一部分:tcp代理 了,记录一下
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示