广播的正确使用

来源:互联网 发布:dbc网络用语 编辑:程序博客网 时间:2024/04/29 16:15

广播正确使用。

(1)注册receiver,首先要考虑的是否动态注册能否满足要求,动态注册能满足要求,则使用动态注册,动态注册是调用registerReceiver函数,如果不需要监听,则及时调用unregisterReceiver。函数原型如下:
    public Intent registerReceiver(BroadcastReceiver receiver,
                                            IntentFilter filter);
    public Intent registerReceiver(BroadcastReceiver receiver,
                                            IntentFilter filter,
                                            String broadcastPermission,
                                            Handler scheduler);
public void unregisterReceiver(BroadcastReceiver receiver);
 (2) 如果要求进程不在运行,也要被拉起处理该Intent,才可以使用静态注册,,在AndroidManifest.xml中定义
       <receiver
            android:name=".bluetooth.BluetoothDiscoveryReceiver">
            <intent-filter>
                <action android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
                <action android:name="android.bluetooth.adapter.action.DISCOVERY_FINISHED" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </receiver>
(3)静态注册和调用sendOrderedBroadcast的消息都登记到串行队列中,优先级较低,系统消息队列中的所有消息必须序列化,一个完成,另一个才能发送,很容易形成系统消息阻塞,使用时,要重视。
(4)在广播处理函数onReceive中不要有睡眠、阻塞、长时间停留操作,必须简短处理,如发送一个异步消息给UI handler,或者开启线程处理,尤其对于静态注册和sendOrderedBroadcast的消息。onReceive长时间处理不仅会导致应用UI线程本身堵塞,而且可能会导致整个系统的消息堵塞。
BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            String action = intent.getAction();
            if (Intent.ACTION_BOOT_COMPLETED.equals(action)
                    || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
                Slog.v(TAG, "Sending password expiration notifications for action " + action);
                mHandler.post(new Runnable() {
                    public void run() {
                        handlePasswordExpirationNotification();
                    }
                });
            }
        }
};
或可以用goAsync()方法:

 public class AppBroadcastReceiver extends BroadcastReceiver {
        private static final String TAG = "AppBroadcastReceiver";
        private static Handler sAsyncHandler;
        static {
            HandlerThread thr = new HandlerThread("filebrowserReceiver Thread");
            thr.start();
            sAsyncHandler = new Handler(thr.getLooper());
        }
  public void onReceive(Context ctx, Intent intent) {
            final PendingResult result = goAsync();
            Runnable worker = new Runnable() {
                @Override
                public void run() {
                    //业务逻辑
                    result.finish();
                }
            };
            sAsyncHandler.post(worker);
        }
onReceive如果太耗时,可能导致“Application No Response”。
有一个小概率事件(不允许后台进程条件下或内存严重不足)
onReceive方法需要耗时操作,有些情况不适合时直接new thread,如应用没有界面、没有服务情况下,因为onReceiver函数一旦返回,则变成后台空进程,优先级降低,则导致子线程可能在没有执行完,应用就被杀死。可以统一搞个Service,在Service生命周期内完成,提高应用优先级,避免被杀。
Android提供的一种异步处理receiver机制,goAsync,goAsync启动了非UI线程,又保证了是前台优先级别。(还需要再验证下是否存在会不会及时触发队列的下一个receiver。)
 (5) 如果要避免不运行的应用则不会被拉起。只有动态注册的receiver能够收到,则Intent携带FLAG_RECEIVER_REGISTERED_ONLY标记即可,如:
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
    intent.addFlags(Intent. FLAG_RECEIVER_REGISTERED_ONLY);
mContext.sendBroadcast(intent);
(6) 如果要避免一个消息在同一时刻多次发送,receiver多次收到同一消息做重复的事情,Intent携带FLAG_RECEIVER_REPLACE_PENDING标记即可,尤其对于粘性广播更要如此。如:
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.addFlags(Intent. FLAG_RECEIVER_REPLACE_PENDING);
mContext.sendBroadcast(intent);
(7)如果要提高超时级别,目前系统有两个超时级别,如果要对响应要求较高,则可以设置超时级别
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
    intent.addFlags(Intent. FLAG_RECEIVER_FOREGROUND);
mContext.sendBroadcast(intent);
一般不需要,有特别需求。目前系统只有电话及亮屏相关广播有此需求。
(8)不要在静态注册的receiver中,收到消息就自杀,非常不合理,如果一个频繁接收到的消息,会导致反复自杀,会很耗系统资源。
(9)无论是静态注册,还是动态注册,IntentFilter尽量精准匹配,避免一个广播拉起一些无关的receiver,一个receiver去处理无关的Intent消息,要求IntentFilter要写的严格些。
(10)多个不同的业务尽量不要使用相似的Intent,相似业务使用同一个receiver,发送者一定要以categories或data等进行区分,并告诉接收者精确匹配。
(11)支持多用户环境的广播一定要使用sendBroadcastAsUser、sendOrderedBroadcastAsUser
不带AsUser的sendOrderedBroadcast、sendBroadcast 只适合当前用户(user)接收。
(12) 进程内部通信,不要使用跨进程广播通信,使用LocalBroadcastManager,或Message即可。
跨进程需要互相通知场景下,尽量使用aidl的服务机制,保证响应及时性。

 

power by 弹跳

 


0 0
原创粉丝点击