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

来源:互联网 发布:下载skype软件 编辑:程序博客网 时间:2024/06/04 20:08

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


Android广播

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

接收系统广播

    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在未启动的时候也能接收广播。

本地广播优势:

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

所以,在跟踪运动轨迹的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稳定。

实现过程:

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

下载Demo;

2 0