Android——BroadCaseReceiver,跟踪轨迹获取稳定的GPS

xiaoxiao2021-02-28  175

因为在跟踪GPS轨迹的时候开启了一个新的service来记录GPS数据,将结果显示在主页面,采用的是在service中使用broadCastReceiver发送广播在activity中收到广播后更新界面,在这学习一下broadCastReceiver。


Android广播

标准广播 完全异步执行的广播,广播发出后,所有广播接收器几乎同一时刻接收到这条广播消息,无先后顺序。效率高,无法被截断。有序广播 同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播消息,当这个广播接收器中的逻辑执行完毕后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器就可以先收到广播消息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播消息了。

接收系统广播

Android内置系统级别的广播,可在自己的APP中通过监听这些广播得到各种系统的状态信息。 广播接收器可自由地对自己感兴趣的广播进行注册,当有相应的关闭发出时,节能收到该广播。 注册广播的方式: 动态注册——Java代码中注册,一定要取消注册——销毁时unregisterReceiver;可自由的控制注册和注销,在灵活性方面有很大的优势,即必须在程序启动之后才能接受到广播。 静态注册——在AndroidMainfest.xml中注册。可在APP未启动的状态下就能接收到广播。在<application>标签内新建一个新的标签<receiver>所有的静态注册的广播接收器都在此注册。在<intent-filter>中加入想要的广播。

创建广播接收器: 新建一个类继承BroadCastReceiver,并重写父类的onReceive()方法。 注意:不要在onReceive()中添加过多的逻辑或进行任何耗时操作,因为广播接收器中不允许开启线程

发送自定义广播 广播——可跨进程的通信方式,我们的APP内发出的广播其他的APP也可接收到。 1. 发送标准广播 sendBroadcast() 2. 发送有序广播 系统会根据接收者声明的优先级别按顺序逐个执行接收者,前面的接收者有权终止广播(BroadcastReceiver.abortBroadcast()),如果广播被前面的接收者终止,后面的接收者就再也无法获取到广播。对于有序广播,前面的接收者可以将处理结果存放进广播Intent,然后传给下一个接收者。 sendOrderedBroadcast(),前面的广播可以将广播截断阻止继续传播。 设定广播的先后顺序: ①在注册的时候修改AndroidManifest.xml中的代码,android:priority的值。数越大优先级别越高,取值范围:-1000到1000。 ②调用IntentFilter对象的setPriority()进行设置,被接收者依次接收广播。

当BroadcastReceiver在10秒内没有执行完毕,Android会认为该程序无响应。所以在BroadcastReceiver里不能做一些比较耗时的操作,否侧会弹出ANR(Application No Response)的对话框。如果需要完成一项比较耗时的工作,应该通过发送Intent给Service,由Service来完成。而不是使用子线程的方法来解决,因为BroadcastReceiver的生命周期很短(在onReceive()执行后BroadcastReceiver 的实例就会被销毁),子线程可能还没有结束BroadcastReceiver就先结束了。如果BroadcastReceiver结束了,它的宿主进程还在运行,那么子线程还会继续执行。但宿主进程此时很容易在系统需要内存时被优先杀死,因为它属于空进程(没有任何活动组件的进程)。

本地广播机制 安全问题——之前讨论的发送接收的广播全部都是属于西永全局广播,即发出的广播可以被其他任何APP接收到,且可接收来自其他任何APP的广播。

本地广播机制——发出的广播只能够在APP内部进行传递,且广播接收器也只能接收来自自身APP发出的广播。

实现——使用LocalBroadcastManager对广播进行管理。

注:本地广播无法通过静态注册方式来接收。 静态广播——让APP在未启动的时候也能接收广播。

本地广播优势:

明确知道正在发送的广播不会离开我们的APP,不必担心数据泄露。其他APP无法将广播发送到该APP内,不必担心有安全漏洞隐患。发送本地广播比发送全局广播更高效。

所以,在跟踪运动轨迹的APP中采用本地广播的方式。

想法: 通过学习关于广播与广播接收器后的想法,看的大牛们请批评指正;

关于百度网盘中的备份问题,关于短信备份, 百度网盘在permission中申请SMS相关权限申请静态的广播接收器(不打开百度网盘的时候也可将接受到的新的信息直接备份)收到短信后将信息发送至相应用户的服务器上。(是否考虑创建一种APP没有界面,直接将新信息发送到指定的服务器完成短信监听)。 这只是考虑到新的信息的备份,还有删除信息后短信的备份。

百度网盘中短信备份肯定不只这一点,但是可以做一个新的短信管理的APP,功能:收信息+屏蔽黑名单信息+信息分类(个人还是广告);

加入相关权限用静态方式注册接受广播不显示黑名单信息:在接收到新信息后在onReceive()方法中,加入短信来源的判断,是否为黑名单用户,如果是黑名单信息,退出;否则继续。显示信息类型:根据新信息的手机号判断是个人信息还是广告类型;

关于百度网盘手机忘带功能分析:

记得百度网盘有手机忘带的功能,让用户不错过短信与电话的功能;开相关的权限监听短信与电话,坚挺到后上传至服务器,服务器在通知pc端的用户。

生命周期

广播接收者的生命周期非常短暂,在接收到广播的时候创建,onReceive()方法结束时销毁。

广播接收者中不要做耗时工作,否则弹出Application No Response(ANR)错误对话框。

最好也不要在广播接收者中创建子线程做耗时操作,因为广播接收者呗销毁后进城就成为空进程,很容易被系统kill掉。耗时的较长的工作最好放在服务中完成。

自己的广播只让指定APP接收

自己的应用 动态——本地广播localBroadCastManager管理;在发送广播的时候给自己发送的广播添加自定义权限: <permission Android:name = "com.ppl.android.permission" android:protectionLevel="normal"></permission> <users-permission android:name= "com.ppl.android.permission">

其他应用

必须知道要是用的广播的权限,然后再自己的清单文件中配置:

最终广播接收者 最终广播接收者——自己APP发送有序广播时通过ContextWrapper.sendOrderdBroadcast()方法指定当前APP下的广播,该广播可能被执行两次。①作为普通广播按优先级接收广播②作为final receiver必须接收一次。——不懂


广播的优先级对无序广播也生效。


动态注册广播的优先级——谁先注册谁优先级高。


判断当前的BroadCastReceiver接收到的是有序广播还是无序广播? 在onReceiver()方法中,调用Boolean b = isOrderdBroadcast(); 该方法是BroadCastReceiver类中提供。

———-

理论分析结束,上代码

一,广播接收类; 方法:创建BroadcastReceiver的子类,由于BroadcastReceiver本质上是一种监听器,所以创建BroadcastReceiver的方法也非常简单,只需要创建一个BroadcastReceiver的子类然后重写onReceive (Context context, Intentintent)方法即可。

public class MyBroadcastReceiver extends BroadcastReceiver{ @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Log.e("MyBroadcastReceiver", "MyBroadcastReceiver onReceive!"); } }

二、注册广播 一旦实现了BroadcastReceiver,接下就应该指定该BroadcastReceiver能匹配的Intent即注册BroadcastReceiver。

静态注册: 这种方法是在配置AndroidManifest.xml配置文件中注册,通过这种方式注册的广播为常驻型广播,也就是说如果应用程序关闭了,有相应事件触发程序还是会被系统自动调用运行。

<!-- 在配置文件中注册BroadcastReceiver能够匹配的Intent --> <receiver android:name="com.ppl.broadcastreceiver.MyBroadcastReceiver" > <intent-filter> <action android:name="android.intent.action.MyBroadcastReceiver" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver>

动态注册 这种方法是通过代码在.Java文件中进行注册。通过这种方式注册的广播为非常驻型广播,即它会跟随Activity的生命周期,所以在Activity结束前我们需要调用unregisterReceiver(receiver)方法移除它。

//通过代码的方式动态注册MyBroadcastReceiver private void registerMyReceiver() { MyBroadcastReceiver recevier = new MyBroadcastReceiver(); IntentFilter filter = new IntentFilter(); filter.addAction("android.intent.action.MyBroadcastReceiver"); registerReceiver(recevier, filter); }

注意,在实际应用中,我们在Activity或Service中注册了一个BroadcastReceiver,当这个Activity或Service被销毁时如果没有解除注册,系统会报一个异常,提示我们是否忘记解除注册了。所以,记得在特定的地方执行解除注册操作:

@Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unregisterReceiver(recevier); }

三、发送广播 当注册完成之后,这个接收者就可以正常工作了。我们可以用以下方式向其发送一条广播。

public void sendBroadcast(View view){ Intent intent = new Intent("android.intent.action.MyBroadcastReceiver"); sendBroadcast(intent); }

结果:


完成基本的用法,接下来有序广播

静态注册方式: 再新建一个广播接收器MyBroadcastReceiverSecond

public class MyBroadcastReceiverSecond extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub Log.e("MyBroadcastReceiverSecond", "MyBroadcastReceiverSecond onReceive!"); } }

在Manifest清单中注册:

<receiver android:name="com.ppl.broadcastreceiver.MyBroadcastReceiver" > <intent-filter android:priority="100"> <action android:name="android.intent.action.MyBroadcastReceiver" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver> <receiver android:name="com.ppl.broadcastreceiver.MyBroadcastReceiverSecond" > <intent-filter android:priority="99"> <action android:name="android.intent.action.MyBroadcastReceiver" /> <category android:name="android.intent.category.DEFAULT" /> </intent-filter> </receiver>

直接发送:

public void sendBroadcast(View view){ Intent intent = new Intent("android.intent.action.MyBroadcastReceiver"); sendBroadcast(intent); }

执行后的结果:


动态注册,发送有序广播 直接发送:

MyBroadcastReceiver recevier; MyBroadcastReceiverSecond receiverSecond; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); registerMyReceiver(); registerMyReceiverSecond(); } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); unregisterReceiver(recevier); unregisterReceiver(receiverSecond); } private void registerMyReceiver() { recevier = new MyBroadcastReceiver(); IntentFilter filter = new IntentFilter(); filter.setPriority(99); filter.addAction("android.intent.action.MyBroadcastReceiver"); registerReceiver(recevier, filter); } private void registerMyReceiverSecond() { receiverSecond = new MyBroadcastReceiverSecond(); IntentFilter filter = new IntentFilter(); filter.setPriority(101); filter.addAction("android.intent.action.MyBroadcastReceiver"); registerReceiver(receiverSecond, filter); } public void sendBroadcast(View view){ Intent intent = new Intent("android.intent.action.MyBroadcastReceiver"); sendBroadcast(intent); }

结果: 截断: 当发送方式为无序广播的时候,当用abortBroadcast()的时候会报错:

BroadcastReceiver trying to return result during a non-ordered broadcast

结论 发送普通广播的时候:广播为异步发送所有广播接收者都能收到广播;且优先级也有效。 只有在发送有序广播的时候,截断才能执行!


结合我的计划轨迹跟踪的APP代码分析

先写我的逻辑 在地图页面显示开始按钮,其实开始并不是开始记录轨迹 而是开始搜索GPS,直至GPS稳定。

实现过程:

点击开始 开启service 去搜索GPS状态;动态注册一个本地BroadCastReceiver,用于接收GPS状态稳定信息。取消搜索GPS状态时,记得取消BroadCastReceiver的注册和stopService;当GPS状态稳定时,“开始”按钮可以点击,点击开始后,返回主页面,并携带 开始 数据;

下载Demo;

转载请注明原文地址: https://www.6miu.com/read-33306.html

最新回复(0)