android开发分享安卓广播基本用法和实战:模拟强制下线

参考资料:郭霖老师第一行代码第二版第五章一.什么是广播在Android中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制。在生活中,我们的收音机的广播电台需要调到特定的频率才能接收到内容,在android中也是一样,通过sendBroadcast来发送广播并携带一个action,只有接收者的action和发送者action相同,才可以接收到这个广播.二.广播有什么用…

目录

一.什么是广播

二.广播有什么用

3.注册广播

4.其他

5.创建方法

四.发送自定义广播(即非系统广播)

 

六.实战:模拟强制下线

kotlin版本代码:

动态注册

静态注册:

自定义广播:

发送有序广播

强制下线功能


参考资料:郭霖老师第一行代码第二版第五章

一.什么是广播

在Android中,Broadcast是一种广泛运用的在应用程序之间传输信息的机制。在生活中,我们的收音机的广播电台需要调到特定的频率才能接收到内容,在android中也是一样,通过sendBroadcast来发送广播并携带一个action,只有接收者的action和发送者action相同,才可以接收到这个广播.

二.广播有什么用

监听应用发出的广播消息,并且做出响应,包括不同组件之间的通信,应用与应用之间的都可以监听到

组件之间:比如当手机电量到30的时候,我在页面弹出一个框

应用之间:打开淘宝时支付时唤起支付宝

3.注册广播

1.动态注册
在代码中注册
2.静态注册
在manifest中注册

动态和静态区别:静态广播的生存期比动态广播的长很多.

             动态广播无需在manifest中注册,而静态广播需要

注意有时候而且有时候需要一些权限

Android8.0之后,所有隐式广播(没有指定发送到哪个应用程序的广播,大多数系统广播属于隐式广播)不允许使用静态注册的方法

 

4.其他

标准广播

有序广播:即多个广播可以设置优先级,发送的时候是sendOrderBroadcast(action),可以在manifest中的receiver中设置android:priority:"100"来设置优先级,也可以使用abortBroadcast()来阻断后面的广播

本地广播:全局广播可以被其他程序接收到,本地广播不会,需要多加LocalBroadcastManager

5.创建方法

动态广播:

Intent intent = new Intent(action写在里面); sendBroadcast(intent);

在另一个活动中(一般是BaseActivity)里:一个IntentFilter来接收action,一个继承了BroadCast的Receiver,注册一下,注销一下就可以i

 

静态广播:通过编译器新建一个Receiver,某一个活动发出action,Receiver来接收,要自己在manifest里设置action

 

举栗代码:

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_CHANGE");         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) {             Toast.makeText(context,"network changes",Toast.LENGTH_LONG).show();         }     } }

代码解释:
首先定义了一个IntentFilter(意图过滤器).然后新建一个类去继承了BroadReceiver这个类,然后在onceiver方法里去写你要接受什么样的广播就行了.然后调用registerReceiver方法注册,最后在ondestory中取消了注册即可.

问题:IntentFilter这个东西是干嘛的呢?
答:主要用来过滤隐式意图。当用户进行一项操作的时候,Android系统会根据配置的 “意图过滤器”来寻找可以响应该操作的组件,服务。当网络变化时,系统发出的就是一条android.net.conn.CONNECTIVITY_CHANGE的广播,所以我们就用IntentFilter把它捕获.

注意:动态注册的广播注册器一定要取消注册才行.

第二步:
因为这里我们要访问系统的网络,所以需要声明权限,在manifest下

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

然后我们运行程序,点击home键,在模拟机上找到控制手机流量开关的地方,打开关闭流量即看到toast弹出(先把wifi那个关了,才有反应,在实体手机上似乎是只在应用内部显示,无法在全局显示)

 

安卓广播基本用法和实战:模拟强制下线

 

改进只显示网络变化不够,还要知道是网络是打开还是关闭:
所以就在onReceive方法中改:

class NetworkChangeReceiver extends BroadcastReceiver{          @Override         public void onReceive(Context context, Intent intent) {             ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService                     (Context.CONNECTIVITY_SERVICE);             NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();             if(networkInfo != null && networkInfo.isConnected()){                 Toast.makeText(context,"移动网络打开",Toast.LENGTH_SHORT).show();             }             else{                 Toast.makeText(context,"移动网络关闭",Toast.LENGTH_SHORT).show();              }          }     }

 

解释:ConnectivityManager这个类有很多作用,可以用来监控网络连接
getSystemService:系统服务,然后参数是要获取的系统服务,如这里就获取了连接服务
然后调用connectivityManager的一个方法getActiveNetworkInfo()去获取网络状态

安卓广播基本用法和实战:模拟强制下线

四.发送自定义广播(即非系统广播)

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"     xmlns:app="https://schemas.android.com/apk/res-auto"     xmlns:tools="https://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="vertical"     tools:context=".SecondActivity">  <EditText      android:id="@+id/account"      android:hint="请输入你的账号"      android:layout_width="match_parent"      android:layout_height="wrap_content" />  <EditText      android:id="@+id/password"      android:hint="请输入你的密码"      android:layout_width="match_parent"      android:layout_height="wrap_content" />  <Button      android:id="@+id/login"      android:layout_gravity="center"      android:text="登录"      android:layout_width="wrap_content"      android:layout_height="wrap_content" /> </LinearLayout> 
package com.example.myapplication;  import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.support.v4.content.LocalBroadcastManager; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.TextView; import android.widget.Toast;  public class MainActivity extends AppCompatActivity {     private TextView textView;     Context context;     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_main);         textView =findViewById(R.id.textview);         textView.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View v) {                   Intent intent = new Intent("broadcast");                 //需要加上下面这一句,不然收不到广播,第一个参数为包名,第二个参数为广播接收器                 intent.setComponent(new ComponentName("com.example.myapplication","com.example.myapplication.MyReceiver"));                 intent.putExtra("content","你的账号"+account.getText().toString()+"你的密码"+password.getText().toString());                 sendBroadcast(intent);             }         });     } }

新建一个接收器

package com.example.myapplication;  import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.widget.Toast;  public class MyReceiver extends BroadcastReceiver {      @Override     public void onReceive(Context context, Intent intent) {       String content = intent.getStringExtra("content");       Toast.makeText(context,content,Toast.LENGTH_SHORT).show();     } }

在manifests中,把要接收的action写好,所以是一个静态广播

<receiver             android:name=".MyReceiver">             <intent-filter>                 <action android:name="broadcast" />             </intent-filter>         </receiver>

 

六.实战:模拟强制下线

因为我们在被强制下线时不知道在哪个界面,所以首先创建一个ActivityColletor来作为专门的集合类对所有活动进行管理

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();          }      }      activities.clear();  } }

通过上面的集合类进行活动的管理,还要有一个类BaseActivity作为所有活动的父类去接受广播,这样不管你在哪个活动中都可以通过父类BaseActivity去调用开放方法finishAll去终结活动.(在这里还有一个需要注意的地方,就是我们的取消注册接收器放在了onPause()方法中,这样就是为了当一个activity失去栈顶位置就会自动取消广播接收器的注册.)

public class BaseActivity extends AppCompatActivity {      private OfflineReceiver offlineReceiver;      @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         ActivityCollector.addActivity(this);     }      @Override     protected void onResume() {         super.onResume();         IntentFilter intentFilter = new IntentFilter();         intentFilter.addAction("offline");         offlineReceiver = new OfflineReceiver();         registerReceiver(offlineReceiver,intentFilter);      }      @Override     protected void onPause() {         super.onPause();         if (offlineReceiver != null){             unregisterReceiver(offlineReceiver);         }      }      @Override     protected void onDestroy() {         super.onDestroy();         ActivityCollector.removeActivity(this);     }     class OfflineReceiver extends BroadcastReceiver{          @Override         public void onReceive(Context context, final Intent intent) {             AlertDialog.Builder builder = new AlertDialog.Builder(BaseActivity.this);             builder.setMessage("你被强制下线");             builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {                 @Override                 public void onClick(DialogInterface dialog, int which) {                     ActivityCollector.finishAll();                     Intent intent1 = new Intent(BaseActivity.this,ThirdActivity.class);                     startActivity(intent1);                 }             });             builder.show();         }     } }

第三个activity:(实现登录)

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"     xmlns:app="https://schemas.android.com/apk/res-auto"     xmlns:tools="https://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="vertical">     <EditText         android:id="@+id/account"         android:hint="请输入你的账号"         android:layout_width="match_parent"         android:layout_height="wrap_content" />     <EditText         android:id="@+id/password"         android:hint="请输入你的密码"         android:layout_width="match_parent"         android:layout_height="wrap_content" />     <Button         android:id="@+id/login"         android:layout_gravity="center"         android:text="登录"         android:layout_width="wrap_content"         android:layout_height="wrap_content" /> </LinearLayout>  

 

public class ThirdActivity extends BaseActivity{     private EditText account;     private EditText password;     private Button Login;     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_third);         account = findViewById(R.id.account);         password = findViewById(R.id.password);         Login = findViewById(R.id.login);         Login.setOnClickListener(new View.OnClickListener() {             @Override             public void onClick(View v) {                 String content = account.getText().toString();                 String content1 = password.getText().toString();                 if (content.equals("admin")&&content1.equals("123456")){                     Intent intent = new Intent(ThirdActivity.this,fourth.class);                     startActivity(intent);                 }                 else {                     AlertDialog.Builder builder = new AlertDialog.Builder(ThirdActivity.this);                     builder.setMessage("用户名或密码错误");                     builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {                         @Override                         public void onClick(DialogInterface dialog, int which) {                          }                     });                     builder.show();                 }             }         });     } }

第四个acticvity,实现强制下线

<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="https://schemas.android.com/apk/res/android"     xmlns:app="https://schemas.android.com/apk/res-auto"     xmlns:tools="https://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     android:orientation="vertical"     tools:context=".fourth"> <Button     android:id="@+id/force_offline"     android:text="强制下线"     android:layout_marginTop="25dp"     android:layout_gravity="center_horizontal"     android:layout_width="wrap_content"     android:layout_height="wrap_content" /> </LinearLayout> 

 

package com.example.myapplication;  import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.support.v7.app.AlertDialog; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button;  public class fourth extends BaseActivity {     private Button force;     @Override     protected void onCreate(Bundle savedInstanceState) {         super.onCreate(savedInstanceState);         setContentView(R.layout.activity_fourth);         force = findViewById(R.id.force_offline);        force.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                Intent intent = new Intent("offline");                sendBroadcast(intent);            }        });     } }

kotlin版本代码:

一个监听时间变化的系统广播:一分钟toast一次

动态注册

class BroadcastActivity : AppCompatActivity() {     lateinit var timeChangeReceiver: TimeChangeReceiver     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_broadcast)         val intentFilter = IntentFilter()         intentFilter.addAction("android.intent.action.TIME_TICK")         timeChangeReceiver = TimeChangeReceiver()         registerReceiver(timeChangeReceiver, intentFilter)     }      override fun onDestroy() {         super.onDestroy()         unregisterReceiver(timeChangeReceiver)     }      inner class TimeChangeReceiver : BroadcastReceiver() {         override fun onReceive(context: Context?, intent: Intent?) {             Toast.makeText(context, "Time has changed", Toast.LENGTH_SHORT).show()         }     } }

安卓广播基本用法和实战:模拟强制下线

静态注册:

前面说了Android8.0之后隐式广播不允许静态注册,而以下这个开机广播比较特殊,还可以使用静态注册

可以通过新建一个Broadcast Receiver来创建一个广播接收者

安卓广播基本用法和实战:模拟强制下线

 

class BootCompleteReceiver : BroadcastReceiver() {      override fun onReceive(context: Context, intent: Intent) {         Toast.makeText(context, "Boot Complete", Toast.LENGTH_SHORT).show()     } }

 最后需要在manifest中写权限:

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
 <receiver             android:name=".other.BootCompleteReceiver"             android:enabled="true"             android:exported="true">             <intent-filter>                 <action android:name="android.intent.action.BOOT_COMPLETED" />             </intent-filter>         </receiver>

运行结果:

安卓广播基本用法和实战:模拟强制下线

自定义广播:

这里使用静态广播去接收一个按钮发出来的广播

class MyReceiver : BroadcastReceiver() {     override fun onReceive(context: Context, intent: Intent) {         Toast.makeText(context, "received in MyBroadcastReceiver", Toast.LENGTH_SHORT).show()     } } 

这里定义我们的action,一会发广播时就要匹配这个值

 <receiver             android:name=".other.MyReceiver"             android:enabled="true"             android:exported="true">             <intent-filter>                 <action android:name="com.example.timingdemo.other.MY_BROADCAST" />             </intent-filter>         </receiver>

 默认情况下我们发出的自定义广播为隐式广播,所以一定要调用setPackage()方法

button.setOnClickListener {             val intent = Intent("com.example.timingdemo.other.MY_BROADCAST")             intent.setPackage(packageName) //这一行必须加,否则为隐式广播无法被接收             sendBroadcast(intent)         }

安卓广播基本用法和实战:模拟强制下线

发送有序广播

定义另外一个Receiver

class AnotherBroadcastReceiver : BroadcastReceiver() {      override fun onReceive(context: Context, intent: Intent) {         Toast.makeText(context, "received in AnotherBroadcastReceiver", Toast.LENGTH_SHORT).show()     } }

 设定优先级

<receiver             android:name=".other.AnotherBroadcastReceiver"             android:enabled="true"             android:exported="true">             <intent-filter android:priority="50">                 <action android:name="com.example.timingdemo.other.MY_BROADCAST" />             </intent-filter>         </receiver>         <receiver             android:name=".other.MyReceiver"             android:enabled="true"             android:exported="true">             <intent-filter android:priority="100">                 <action android:name="com.example.timingdemo.other.MY_BROADCAST" />             </intent-filter>         </receiver>

改用这个方法即可 sendOrderedBroadcast(intent, null)

 button.setOnClickListener {             val intent = Intent("com.example.timingdemo.other.MY_BROADCAST")             intent.setPackage(packageName) //这一行必须加,否则为隐式广播无法被接收             sendOrderedBroadcast(intent, null)         }

如果想要阻断后面的广播,使用

abortBroadcast()

强制下线功能

与上面那个功能一样,只不过改为了kotlin版本

object ActivityCollector {     private val activities = ArrayList<Activity>()      fun addActivity(activity: Activity){         activities.add(activity)     }      fun removeActivity(activity: Activity){         activities.remove(activity)     }      fun finishAll(){         for (activity in activities) {             if (!activity.isFinishing){                 activity.finish()             }         }         activities.clear()     } }
open class BaseActivity : AppCompatActivity() {     lateinit var receiver: ForceOfflineReceiver      override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         ActivityCollector.addActivity(this)     }      override fun onDestroy() {         super.onDestroy()         ActivityCollector.removeActivity(this)     }      override fun onResume() {         super.onResume()         val intentFilter = IntentFilter()         intentFilter.addAction("com.example.timingdemo.base.FOR_OFFCE_OFFLINE")         receiver = ForceOfflineReceiver()         registerReceiver(receiver, intentFilter)     }      override fun onPause() {         super.onPause()         unregisterReceiver(receiver)     }      inner class ForceOfflineReceiver : BroadcastReceiver() {         override fun onReceive(context: Context, intent: Intent?) {             AlertDialog.Builder(context).apply {                 setTitle("Warning")                 setMessage("you are forced to be offline. please try to login again.")                 setCancelable(false)                 //如果lambda参数未使用,可以使用下划线来替代,只有一个参数时可以使用it来代替                 setPositiveButton("OK") { _ , _ ->                     ActivityCollector.finishAll()                     val intent = Intent(context, LoginActivity::class.java)                     context.startActivity(intent)                 }                 show()             }         }     } } 
class LoginActivity : BaseActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_login)         val accountEdit = findViewById<EditText>(R.id.accountEdit)         val passwordEdit = findViewById<EditText>(R.id.passwordEdit)         login.setOnClickListener {             val account = accountEdit.text.toString()             val password = passwordEdit.text.toString()             if (account == "admin" && password == "123") {                 val intent = Intent(this, Main2Activity::class.java)                 startActivity(intent)                 finish()             } else {                 Toast.makeText(this, "account or password is invalid", Toast.LENGTH_SHORT).show()             }         }     } }
class Main2Activity : BaseActivity() {     override fun onCreate(savedInstanceState: Bundle?) {         super.onCreate(savedInstanceState)         setContentView(R.layout.activity_main2)         forceOffLine.setOnClickListener {             val intent = Intent("com.example.timingdemo.base.FOR_OFFCE_OFFLINE")             sendBroadcast(intent)         }     } }
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="https://schemas.android.com/apk/res/android"     xmlns:app="https://schemas.android.com/apk/res-auto"     xmlns:tools="https://schemas.android.com/tools"     android:layout_width="match_parent"     android:layout_height="match_parent"     tools:context=".activity.LoginActivity">      <TextView         android:id="@+id/textView4"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_marginStart="16dp"         android:layout_marginTop="16dp"         android:text="账户"         android:textSize="16sp"         app:layout_constraintStart_toStartOf="parent"         app:layout_constraintTop_toTopOf="parent" />      <TextView         android:id="@+id/textView7"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_marginTop="32dp"         android:text="密码"         android:textSize="16sp"         app:layout_constraintEnd_toEndOf="@+id/textView4"         app:layout_constraintStart_toStartOf="@+id/textView4"         app:layout_constraintTop_toBottomOf="@+id/textView4" />      <Button         android:id="@+id/login"         android:layout_width="wrap_content"         android:layout_height="wrap_content"         android:layout_marginTop="44dp"         android:text="登录"         app:layout_constraintEnd_toEndOf="parent"         app:layout_constraintHorizontal_bias="0.498"         app:layout_constraintStart_toStartOf="parent"         app:layout_constraintTop_toBottomOf="@+id/textView7" />      <EditText         android:id="@+id/accountEdit"         android:layout_width="0dp"         android:layout_height="wrap_content"         android:layout_marginStart="16dp"         android:layout_marginEnd="16dp"         app:layout_constraintBottom_toBottomOf="@+id/textView4"         app:layout_constraintEnd_toEndOf="parent"         app:layout_constraintStart_toEndOf="@+id/textView4"         app:layout_constraintTop_toTopOf="@+id/textView4" />      <EditText         android:id="@+id/passwordEdit"         android:layout_width="0dp"         android:layout_height="wrap_content"         android:layout_marginStart="16dp"         android:layout_marginEnd="16dp"         app:layout_constraintBottom_toBottomOf="@+id/textView7"         app:layout_constraintEnd_toEndOf="parent"         app:layout_constraintStart_toEndOf="@+id/textView7"         app:layout_constraintTop_toTopOf="@+id/textView7" />  </androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

 

本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。

ctvol管理联系方式QQ:251552304

本文章地址:https://www.ctvol.com/addevelopment/892727.html

(0)
上一篇 2021年10月20日
下一篇 2021年10月20日

精彩推荐