美文网首页摘录
安卓广播BroadcastReceiver机制《第一行代码笔记》

安卓广播BroadcastReceiver机制《第一行代码笔记》

作者: 引号123 | 来源:发表于2017-09-13 00:05 被阅读0次

    安卓广播BroadcastReceiver机制《第一行代码笔记》

    标准广播概念

    是一种完全异步执行的广播,在广播发出以后,所有的广播接收器几乎都会在同一时刻接收到这条广播信息,因此他们之间没有先后顺序可言,这样的广播效率会比较高,但同时意味着它是无法被截断的,标准的广播流程如图

    标准广播流程图.jpg

    有序广播概念

    是一种同步执行的广播,在广播发出之后,同一时刻只会有一个广播接收器能够收到这条广播信息,当这个广播接收器逻辑执行完后,广播才会继续传递。所以此时的广播接收器是有先后顺序的,优先级高的广播接收器可以先收到广播信息,并且前面的广播接收器还可以截断正在传递的广播,这样后面的广播接收器就无法收到广播信息了,有序广播的流程如图

    有序广播流程图.jpg

    动态注册监听网络变化

    MainActivity类

    package com.yinhao.broadcasttest;
    
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.support.v4.content.LocalBroadcastManager;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends AppCompatActivity {
    
        private NetworkChangeReceiver receiver;
        private IntentFilter intentFilter;
        
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);        
    
            intentFilter = new IntentFilter();
            intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");//action是添加相应的广播的方法
            receiver = new NetworkChangeReceiver();
            registerReceiver(receiver, intentFilter);
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            unregisterReceiver(receiver);
               }
    }
    
    

    定义一个类集成自BroadcastReceiver

    package com.yinhao.broadcasttest;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.net.ConnectivityManager;
    import android.net.NetworkInfo;
    import android.util.Log;
    import android.widget.Toast;
    
    /**
     * Created by yinhao on 2017/9/11.
     */
    
    public class NetworkChangeReceiver extends BroadcastReceiver {
        private static final String TAG = "NetworkChangeReceiver";
    
        @Override
        public void onReceive(Context context, Intent intent) {
            //专门管理网络连接的系统服务类
            ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
            //得到NetworkInfo的实例
            NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
            if (networkInfo != null && networkInfo.isAvailable()) {//是否有网络的方法
                Toast.makeText(context, "网络可用", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(context, "网络不可用", Toast.LENGTH_SHORT).show();
            }
        }
    }
    
    

    最后加上权限

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    

    静态注册实现开机启动

    写一个类继承自BroadcastReceiver

    package com.yinhao.broadcasttest;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.util.Log;
    import android.widget.Toast;
    
    /**
     * Created by yinhao on 2017/9/12.
     */
    
    public class BootCompleteReceiver extends BroadcastReceiver {
        private static final String TAG = "BootCompleteReceiver";
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
    
            //Log.i(TAG, "onReceive: Boot Complete");
        }
    }
    
    

    在这里注意下,静态注册必须要在manifest中注册,application下

     <!-- enabled是否启用这个广播接收器,export是否允许这个广播接收器接收程序以外的广播 -->
            <receiver
                android:name=".BootCompleteReceiver"
                android:enabled="true"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.BOOT_COMPLETED" />
                </intent-filter>
    
            </receiver>
    

    添加接收开机启动状态权限和相应的action(在上面的代码已经注明)

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    

    发送自定义广播

    1.自定义一个类继承自BroadcastReceiver

    2.记得要在manifest中注册,不过这次intent-filter标签下action标签的name值要写自己创建的这个类,比如在这里我的类名MyBroadcastReceiver,那么name值可以写为:

    <receiver android:name=".MyBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
    
                <intent-filter>
                    <action android:name="com.yinhao.broadcasttest.MyBroadcastReceiver"/>
                </intent-filter>
    
            </receiver>
    

    其实这样定义name值方便自己,里面的值只要是唯一的,你定义什么都可以。

    如何发送呢?
    我们可以写一个按钮点击事件,当我们点击按钮时:

    Button button = (Button) findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent("com.yinhao.broadcasttest.MyBroadcastReceiver");
                    sendBroadcast(intent);
                }
            });
    

    这样我们就完成了发送自定义广播。

    发送有序广播

    我们需要新建另一个项目,定义一个类继承自BroadcastReceiver,在Manifest里添加上一个项目自定义的receiver的name值

    <action android:name="com.yinhao.broadcasttest.MyBroadcastReceiver"/>
    

    这样当我们上一个项目里面的按钮时,就会弹出两个Toast

    我们如何判断这是一个有序广播呢

    我们可以在第一个项目中添加一个值,priority,这是优先权的意思

    <receiver android:name=".MyBroadcastReceiver"
                android:enabled="true"
                android:exported="true">
    
                <intent-filter android:priority="100">
                    <action android:name="com.yinhao.broadcasttest.MyBroadcastReceiver"/>
                </intent-filter>
    
            </receiver>
    

    我们在MainActiviy中sendBroadcast()方法修改为sendOrderBroadcast()

    sendOrderedBroadcast(intent,null);//第一个参数是intent,第二个是跟权限有关的字符串
    

    这样即为发送一个有序广播,而且MyBroadcastReceiver因为优先值高,Toast会优先显示。
    最后我们可以在MyBroadcastReceiver中添加一个方法,abortBroadcast()

    public class MyBroadcastReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show();
            abortBroadcast();//将这条广播截断,后面的广播接收器将无法再收到此条广播
        }
    }
    

    这样当我们点击按钮时,只会弹出一个Toast了,因为此方法将后面的广播截断了,原因是我们之前定义了优先级。

    发送本地广播

    因为安全性的问题,让别的应用无法访问此应用的广播

    新建一个类继承自BroadcastReceiver,因为与上面的一些代码,所以不多展开展示

    public class MainActivity extends AppCompatActivity {
    
      
        private IntentFilter intentFilter;
        private LocalBroadcastManager localBroadcastManager;
        private LocalReceiver localReceiver;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            localBroadcastManager = LocalBroadcastManager.getInstance(this);
    
            Button button = (Button) findViewById(R.id.button);
            button.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent("com.yinhao.broadcasttest.LocalReceiver");
                    localBroadcastManager.sendBroadcast(intent);//发送本地广播
                }
            });
    
            intentFilter = new IntentFilter();
            intentFilter.addAction("com.yinhao.broadcasttest.LocalReceiver");
            localReceiver = new LocalReceiver();
            localBroadcastManager.registerReceiver(localReceiver, intentFilter);//注册本地广播
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            localBroadcastManager.unregisterReceiver(localReceiver);
        }
    }
    
    

    实现强制下线Demo

    MainActivity

    
    package com.yinhao.broadcastreceiverbestpractice;
    
    import android.content.Intent;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    
    public class MainActivity extends BaseActivity {
    
        private Button forceOffline;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            forceOffline = (Button) findViewById(R.id.force_offline);
            forceOffline.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Intent intent = new Intent("com.yinhao.broadcastreceiverbestpractice.FORCE_OFFLINE");
                    sendBroadcast(intent);
                }
            });
        }
    }
    
    
    

    R.layout.activity_main

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <Button
            android:id="@+id/force_offline"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:text="offline" />
    
    </LinearLayout>
    

    LoginActivity

    package com.yinhao.broadcastreceiverbestpractice;
    
    import android.content.Intent;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.Button;
    import android.widget.EditText;
    import android.widget.Toast;
    
    public class LoginActivity extends BaseActivity {
    
        private EditText accountEdit;
        private EditText passwordEdit;
        private Button login;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_login);
            accountEdit = (EditText) findViewById(R.id.account);
            passwordEdit = (EditText) findViewById(R.id.password);
            login = (Button) findViewById(R.id.login);
            login.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    String account = accountEdit.getText().toString();
                    String password = passwordEdit.getText().toString();
                    if (account.equals("admin") && password.equals("123456")) {
                        startActivity(new Intent(LoginActivity.this, MainActivity.class));
                        finish();
                    } else {
                        Toast.makeText(LoginActivity.this, "account or password invalid", Toast.LENGTH_SHORT).show();
                    }
                }
            });
        }
    }
    
    

    activity_login

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:orientation="horizontal">
    
            <TextView
                android:layout_width="90dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:text="Account:"
                android:textSize="18sp" />
    
            <EditText
                android:id="@+id/account"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_weight="1" />
    
        </LinearLayout>
    
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:orientation="horizontal">
    
            <TextView
                android:layout_width="90dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:text="Password:"
                android:textSize="18sp" />
    
            <EditText
                android:id="@+id/password"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center_vertical"
                android:layout_weight="1" />
    
        </LinearLayout>
    
        <Button
            android:id="@+id/login"
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:text="Login" />
    
    </LinearLayout>
    
    

    BaseActivity

    package com.yinhao.broadcastreceiverbestpractice;
    
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.DialogInterface;
    import android.content.Intent;
    import android.content.IntentFilter;
    import android.os.Bundle;
    import android.os.PersistableBundle;
    import android.support.annotation.Nullable;
    import android.support.v7.app.AlertDialog;
    import android.support.v7.app.AppCompatActivity;
    import android.util.Log;
    
    /**
     * Created by yinhao on 2017/9/12.
     */
    
    public class BaseActivity extends AppCompatActivity {
    
        private ForceOfflineReceiver receiver;
        private static final String TAG = "BaseActivity";
    
        @Override
        public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
            super.onCreate(savedInstanceState, persistentState);
            ActivityCollector.addActivity(this);
        }
    
        @Override
        protected void onResume() {
            Log.i(TAG, "onResume: ");
            super.onResume();
            IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction("com.yinhao.broadcastreceiverbestpractice.FORCE_OFFLINE");
            receiver = new ForceOfflineReceiver();
            registerReceiver(receiver, intentFilter);
        }
    
        @Override
        protected void onPause() {
            Log.i(TAG, "onPause: ");
            super.onPause();
            if (receiver != null) {
                unregisterReceiver(receiver);
                receiver = null;
            }
        }
    
        @Override
        protected void onDestroy() {
            super.onDestroy();
            ActivityCollector.removeActivity(this);
        }
    
        class ForceOfflineReceiver extends BroadcastReceiver {
    
            @Override
            public void onReceive(final Context context, Intent intent) {
                AlertDialog.Builder builder = new AlertDialog.Builder(context);
                builder.setTitle("Warning");
                builder.setMessage("You are force to be offline. Please try to login again.");
                builder.setCancelable(false);//将对话框设置为不可取消
                builder.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ActivityCollector.finishAll();//销毁活动
                        context.startActivity(new Intent(context, LoginActivity.class));//重新启动到登录界面
                    }
                });
                builder.show();
            }
        }
    }
    
    

    ActivityCollector

    package com.yinhao.broadcastreceiverbestpractice;
    
    import android.app.Activity;
    
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * Created by yinhao on 2017/9/12.
     */
    
    public class ActivityCollector {
        public static List<Activity> activities = new ArrayList<>();
    
        public static void addActivity(Activity activity) {
            activities.add(activity);
        }
    
        public static void removeActivity(Activity activity) {
            activities.add(activity);
        }
    
        public static void finishAll() {
            for (Activity activity : activities) {
                activity.finish();
            }
        }
    }
    
    

    因为始终需要保证处于栈顶的活动才能接收到这条强制下线的广播,非栈顶的活动不应该也没有必要去接收这条广播。当一个活动失去栈顶时,自动取消广播接收器的注册。

    相关文章

      网友评论

        本文标题:安卓广播BroadcastReceiver机制《第一行代码笔记》

        本文链接:https://www.haomeiwen.com/subject/pjohsxtx.html