網站首頁 編程語言 正文
廣播機制簡介
- 標準廣播:完全異步執行,廣播發出后,所有廣播接收器幾乎都同一時刻收到這條廣播(無法被截斷)
- 有序廣播:同步執行,廣播發出后同一時刻只會有一個廣播接收器能收到這條廣播消息,前面的接收器可以截斷正在傳遞的廣播
接收系統廣播
廣播接收器可在代碼中注冊和AndroidManifest.xml中注冊,前者為動態注冊,后者被稱為靜態注冊。
動態注冊監聽網絡變化
示例代碼:
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView((R.layout.activity_main));
intentFilter= new IntentFilter();
intentFilter.addAction("android.net.conn.CONNECTIVITY_VHANGE");
networkChangeReceiver = new NetworkChangeReceiver();
registerReceiver(networkChangeReceiver, intentFilter);
}
@Override
protected void onDestroy(){
super.onDestroy();
unregisterReceiver(networkChangeReceiver);
}
class NetworkChangeReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
ConnectivityManager connectionManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectionManager.getActiveNetworkInfo();
if(networkInfo != null && networkInfo.isAvailable()){
Toast.makeText(context, "network is available", Toast.LENGTH_SHORT).show();
}else {
Toast.makeText(context, "network is unavailable", Toast.LENGTH_SHORT).show();
}
Toast.makeText(context, "network changes", Toast.LENGTH_SHORT).show();
}
}
}
靜態注冊實現開機啟動
<receiver android:name=".BootCompleteReceiver" android:enabled="true" android:exported="true"></receiver>
Export屬性表示是否允許這個廣播接收器接收本程序以外的廣播,enable表示是否使用這個廣播接收器。
<receiver android:name=".BootCompleteReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver>
添加了filter就可以過濾了
可以通過左鍵新建-》其它來新建靜態注冊廣播
廣播接收器中不允許開線程,當onReceive方法運行較長時間而沒結束時,程序就會報錯,所以其中不能添加過多的邏輯或任何耗時操作。
發送自定義廣播
發送標準廣播
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView((R.layout.activity_main));
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendBroadcast(intent);
}
});
}
通過點擊按鈕發送廣播
public class myBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "receiverd in myBroadcastReceiver", Toast.LENGTH_SHORT).show();
}
}
這里是自定義的接收器
<receiver android:name=".myBroadcastReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter> </receiver>
在xml中定義過濾的廣播類型
發送有序廣播
廣播是一種跨進程的通信方式
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView((R.layout.activity_main));
Button button = (Button)findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View v){
Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendOrderedBroadcast(intent, null);
}
});
}
只需要修改一行代碼 sendOrederedBroadcast即可發送有序廣播,同時在接收器的xml文件中可以設置優先級
<receiver android:name=".myBroadcastReceiver" android:enabled="true" android:exported="true"> <!-- 在這里設置優先級--> <intent-filter android:priority="100"> <action android:name="com.example.broadcasttest.MY_BROADCAST"/> </intent-filter> </receiver>
如果想要在接收到廣播之后就讓廣播停止繼續傳遞呢,修改onReceive的代碼即可
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "receiverd in myBroadcastReceiver", Toast.LENGTH_SHORT).show();
// 停止繼續傳遞
abortBroadcast();
}
使用本地廣播
前面我們發送和接收的廣播全部屬于系統全局廣播,即發出的廣播可以被其他任何應用程序接收到,并且我們也可以接收來自于其他任何應用程序的廣播。這樣就很容易引起安全性的問題,比如說我們發送的一些攜帶關鍵性數據的廣播有可能被其他的應用程序截獲,或者其他的程序不停地向我們的廣播接收器里發送各種垃圾廣播。
使用本地廣播則發出的廣播只能在應用程序內部傳遞,并且接收器也只能接收來自本應用程序發出的廣播。
public class MainActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManger;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
setContentView((R.layout.activity_main));
localBroadcastManger = LocalBroadcastManager.getInstance(this); //獲取實例
Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
localBroadcastManger.sendBroadcast(intent); //發送本地廣播
}
});
intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
localReceiver = new LocalReceiver();
localBroadcastManger.registerReceiver(localReceiver, intentFilter); //注冊本地廣播監聽器
}
@Override
protected void onDestroy(){
super.onDestroy();
localBroadcastManger.unregisterReceiver(localReceiver);
}
class LocalReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent){
Toast.makeText(context, "received local broadcast", Toast.LENGTH_SHORT).show();
}
}
}
代碼的不同主要在于需要首先獲取實例,然后還要有注冊。
需要注意的是,本地廣播無法通過靜態注冊來接收。
使用廣播實現強制下線功能
強制下線功能首先需要實現下關閉所有的活動的功能,新建一個ActivityCollector類管理所有的活動
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.remove(activity);
}
public static void finishAll(){
for(Activity activity:activities){
if(!activity.isFinishing()){
activity.finish();
}
}
}
}
然后創建baseActivity類作為活動的父類,代碼如下:
public class BaseActivity extends AppCompatActivity {
private ForceOfflineReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}
@Override
protected void onResume(){
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE");
receiver = new ForceOfflineReceiver();
registerReceiver(receiver, intentFilter);
}
@Override
protected void 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 forced to be offline");
builder.setCancelable(false);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int which) {
ActivityCollector.finishAll(); //銷毀所有活動
Intent intent = new Intent(context, LoginActivity.class);
context.startActivity(intent); //重新啟動loginActivity
}
});
builder.show();
}
}
}
我們可以注意到,之前編寫注冊和銷毀接收器的時候是在onCreate和onDestroy這兩個函數里的,但是上面代碼中卻寫在了onResume和onPause里面,這是因為我們每次都只需要在棧頂的活動接收廣播,非棧頂活動沒必要接收這條廣播。
除此之外,我們創建一個登陸的活動,在活動頁面上放置輸入框,并編寫登錄邏輯
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".ui.login.LoginActivity"> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="60dp" tools:ignore="MissingConstraints"> <TextView android:layout_width="90dp" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textSize="18sp" android:text="Account:"/> <EditText android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/account" android:layout_weight="1" android:layout_gravity="center_horizontal"/> </LinearLayout> <LinearLayout android:orientation="horizontal" android:layout_width="match_parent" android:layout_height="60dp" tools:ignore="MissingConstraints"> <TextView android:layout_width="90dp" android:layout_height="wrap_content" android:layout_gravity="center_horizontal" android:textSize="18sp" android:text="password:"/> <EditText android:layout_width="0dp" android:layout_height="wrap_content" android:id="@+id/password" android:layout_weight="1" android:layout_gravity="center_horizontal"/> </LinearLayout> <Button android:layout_width="match_parent" android:layout_height="60dp" android:id="@+id/login" android:text="Login" tools:ignore="MissingConstraints"></Button> </androidx.constraintlayout.widget.ConstraintLayout>
public class LoginActivity extends AppCompatActivity {
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();
//如果賬號是admin 且密碼是123456則登錄成功
if(account.equals("admin") && password.equals("123456")){
Intent intent = new Intent(LoginActivity.this, MainActivity.class);
startActivity(intent);
finish();
}else {
Toast.makeText(LoginActivity.this, "account is invalid", Toast.LENGTH_SHORT).show();
}
}
});
}
}
這樣就模擬了登錄的窗口,然后在mainActivity中加入觸發強制下線的代碼
public class MainActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button forceOffline = (Button) findViewById(R.id.force_offline);
forceOffline.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent = new Intent("com.example.broadcastbestpractice.FROCE_OFFLINE");
sendBroadcast(intent);
}
});
}
}
這樣邏輯就差不多了,下面去AndroidManifest.xml中修改下程序入口即可:
原文鏈接:https://blog.csdn.net/qq_35481726/article/details/129113783
- 上一篇:沒有了
- 下一篇:沒有了
相關推薦
- 2023-10-09 react中為什么用箭頭函數來定義事件處理函數
- 2022-10-21 React實現動態調用的彈框組件_React
- 2022-06-01 Android自制九宮格解鎖控件_Android
- 2022-07-10 docker的安裝及常用命令
- 2023-07-16 callBack: function(res){} 與 callBack: res =>{}
- 2023-06-17 pytorch?簡介及常用工具包展示_python
- 2022-07-12 ui追加動態li
- 2022-07-28 XML基本概念XPath、XSLT與XQuery函數介紹_XML/RSS
- 欄目分類
-
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支