本篇文章主要介紹以下幾個知識點:
- 廣播機制的簡介你辣;
- 接收系統(tǒng)廣播:動態(tài)注冊與靜態(tài)注冊;
- 發(fā)送自定義廣播念搬;
- 使用本地廣播;
- 實戰(zhàn):實現(xiàn)強制下線站玄。
5.1 廣播機制簡介
Android 中的廣播主要分兩種類型:標準廣播和有序廣播。
-
標準廣播(Normal broadcasts)
??是一種完全異步執(zhí)行的廣播濒旦,在廣播發(fā)出之后株旷,所有的廣播接收器幾乎都會在同一時刻接收到這條廣播消息,因此它們之間沒有任何先后順序可 言尔邓。這種廣播的效率會比較高晾剖,但同時也意味著它是無法被截斷的。標準廣播的工作流程如下:
-
有序廣播(Ordered broadcasts)
??是一種同步執(zhí)行的廣播梯嗽,在廣播發(fā)出之后齿尽,同一時刻只會有一個廣播接收器能夠收到這條廣播消息,當這個廣播接收器中的邏輯執(zhí)行完畢后灯节,廣播才會繼續(xù)傳遞循头。所以此時的廣播接收器是有先后順序的,優(yōu)先級高的廣播接收器就可以先收到廣播消息炎疆,并且前面的廣播接收器還可以截斷正在傳遞的廣播卡骂,這樣后面的廣播接收器就無法收到廣播消息了。有序廣播的工作流程如下:
5.2 接收系統(tǒng)廣播
Android 內置了很多系統(tǒng)級別的廣播磷雇,我們可以在應用程序中通過監(jiān)聽這些廣播來得到各種系統(tǒng)的狀態(tài)信息。若想要接收到這些廣播躏救,就需要使用廣播接收器唯笙。
5.2.1 動態(tài)注冊監(jiān)聽網(wǎng)絡變化
注冊廣播的方式有兩種,在代碼中注冊(動態(tài)注冊)和在 AndroidManifest.xml
中注冊(靜態(tài)注冊)盒使。
創(chuàng)建一個廣播接收器:新建一個類崩掘,繼承 BroadcastReceiver
, 并重寫父類的 onReceive()
方法少办。當有廣播到來時苞慢,onReceive()
方法就會得到執(zhí)行, 具體的邏輯在這個方法中處理英妓。
接下來先通過動態(tài)注冊的方式編寫一個能夠監(jiān)聽網(wǎng)絡變化的程序挽放,學習一下廣播接收器的基本用法绍赛。代碼如下:
/**
* 廣播,動態(tài)監(jiān)聽網(wǎng)絡變化
*/
public class BroadcastActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private NetworkChangeReceiver networkChangeReceiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
// 創(chuàng)建 IntentFilter 實例
intentFilter = new IntentFilter();
// 添加廣播值
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");
// 創(chuàng)建 NetworkChangeReceiver 實例
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) {
// 獲取管理網(wǎng)絡連接的系統(tǒng)服務類的實例
ConnectivityManager connectivityManager = (ConnectivityManager)
getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
// 判斷網(wǎng)絡是否可用
if (networkInfo != null && networkInfo.isAvailable()){
ToastUtils.showShort("網(wǎng)絡可用");
}else {
ToastUtils.showShort("網(wǎng)絡不可用");
}
}
}
}
注意事項:
- 動態(tài)注冊的廣播接收器一定都要取消注冊才行辑畦,這里我們是在
onDestroy()
方法中通過調用unregisterReceiver()
方法來實現(xiàn)的吗蚌。 - 在
AndroidManifest.xml
文件中加入訪問系統(tǒng)的網(wǎng)絡狀態(tài)權限:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
運行程序,然后按下 Home 鍵→按下 Menu 鍵→System settings→Data usage
進入到數(shù)據(jù)使用詳情界面纯出,關閉 Mobile Data
會彈出網(wǎng)絡不可用的提示:
重新打開 Mobile Data
又會彈出網(wǎng)絡可用的提示:
5.2.2 靜態(tài)注冊實現(xiàn)開機啟動
動態(tài)注冊的廣播接收器可以自由地控制注冊與注銷蚯妇,在靈活性方面有很大的優(yōu)勢,但它也存在著一個缺點暂筝,即必須要在程序啟動之后才能接收到廣播箩言,因為注冊的邏輯是寫在 onCreate()
方法中的。使用靜態(tài)注冊的方式就可以讓程序在未啟動的情況下接收到廣播焕襟。
接下來讓程序接收一條開機廣播陨收,收到這條廣播時在 onReceive()
方法中相應的邏輯,從而實現(xiàn)開機啟動的功能胧洒。Android Studio 創(chuàng)建廣播接收器:右擊com.wonderful.myfirstcode.chapter5(你的包名)→New→Other→Broadcast Receiver
畏吓,會彈出窗口:
這里把廣播接收器命名為 BootCompleteReceiver
,Exported
表示是否允許此廣播接收本程序以外的廣播卫漫,Enabled
表示是否啟用這個廣播接收器菲饼。
點擊 Finish
完成創(chuàng)建后,修改 BootCompleteReceiver
中的代碼:
public class BootCompleteReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
// 執(zhí)行相應的邏輯
ToastUtils.showShort("開機完成");
}
}
靜態(tài)的廣播接收器一定要在 AndroidManifest.xml
文件中注冊才可使用列赎,剛使用 Android Studio 創(chuàng)建的廣播接收器已經自動幫我們完成注冊了宏悦,如下:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.wonderful.myfirstcode">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:name=".MyApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
. . .
<receiver
android:name=".chapter5.BootCompleteReceiver"
android:enabled="true"
android:exported="true"></receiver>
</application>
</manifest>
接下來修改 AndroidManifest.xml
文件中的標簽 <receiver>
中的內容,使 BootCompleteReceiver
接收開機廣播:
<receiver
android:name=".chapter5.BootCompleteReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
由于系統(tǒng)啟動后會發(fā)出一條值為 android.intent.action.BOOT_COMPLETED
的廣播包吝,因此在 <intent-filter>
標簽中添加相應的 action
饼煞。另外,別忘了聲明監(jiān)聽系統(tǒng)開機廣播的權限:
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
這樣程序可以接收到開機廣播了诗越,將模擬器關閉并重啟砖瞧,如下:
注意事項:不要在 onReceive()
方法中添加過多的邏輯或者進行耗時操作,因為廣播接收器中是不允許開啟線程的嚷狞。
5.3 發(fā)送自定義廣播
接下來學習如何在應用程序中發(fā)送自定義廣播块促,通過實踐的方式來看一下標準廣播和有序廣播的區(qū)別。
5.3.1 發(fā)送標準廣播
在發(fā)送廣播之前床未,先新建一個廣播接收器 MyBroadcastReceiver
來接收自定義廣播竭翠,收到廣播時彈提示,代碼如下:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ToastUtils.showShort("收到自定義廣播");
}
}
然后修改 AndroidManifest.xml
文件中的標簽 <receiver>
中的內容薇搁,讓 MyBroadcastReceiver
收到一條值為 com.wonderful.myfirstcode.MY_BROADCAST
的廣播:
<receiver
android:name=".chapter5.MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.wonderful.myfirstcode.MY_BROADCAST" />
</intent-filter>
</receiver>
接下來在布局文件中添加一個按鈕作為發(fā)送廣播的觸發(fā)點:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/btn_send_broadcast"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="發(fā)送廣播"/>
</RelativeLayout>
然后修改 activity
中的代碼斋扰,在按鈕點擊事件中加入發(fā)送自定義廣播邏輯,如下:
public class BroadcastActivity extends AppCompatActivity {
. . .
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
Button btn_send_broadcast= (Button) findViewById(R.id.btn_send_broadcast);
btn_send_broadcast.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 構建 Intent 對象
Intent intent = new Intent("com.wonderful.myfirstcode.MY_BROADCAST");
// 發(fā)送廣播
sendBroadcast(intent);
}
});
. . .
}
. . .
}
運行程序,點擊按鈕传货,效果如下:
這樣就完成了發(fā)送自定義廣播的功能屎鳍。另外,由于廣播是使用 Intent
進行傳遞的损离,因此你還可以在 Intent
中攜帶一些數(shù)據(jù)傳遞給廣播接收器哥艇。
5.3.1 發(fā)送有序廣播
廣播是一種可以跨進程的通信方式,這一點從前面接收系統(tǒng)廣播的時候可以看出來僻澎。因此在我們應用程序內發(fā)出的廣播貌踏,其他的應用程序應該也是可以收到的。為了驗證這一點窟勃,我們需要再新建一個 BroadcastTest2
項目祖乳。
項目創(chuàng)建好后,定義一個接收上一小節(jié)中的自定義廣播的廣播接收器 AnotherBroadcastReceiver
秉氧,如下:
public class AnotherBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Toast.makeText(context, "另外一個廣播接收器收到廣播了眷昆!", Toast.LENGTH_SHORT).show();
}
}
然后修改 AndroidManifest.xml
文件中的標簽 <receiver>
中的內容,讓 AnotherBroadcastReceiver
同樣收到一條值為 com.wonderful.myfirstcode.MY_BROADCAST
的廣播:
<receiver
android:name=".AnotherBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.wonderful.myfirstcode.MY_BROADCAST" />
</intent-filter>
</receiver>
現(xiàn)在把項目 BroadcastTest2
安裝到模擬器上汁咏,然后重新回到上一個項目的界面上亚斋,點擊發(fā)送廣播按鈕,就會彈兩次提示信息攘滩,如圖:
到目前為止帅刊,發(fā)送的都是標準廣播,接下來嘗試一下發(fā)送有序廣播漂问。 回到前面的項目赖瞒,修改 Activity
中的代碼,如下:
public class BroadcastActivity extends AppCompatActivity {
. . .
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
Button btn_send_broadcast = (Button) findViewById(R.id.btn_send_broadcast);
btn_send_broadcast.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 構建 Intent 對象
Intent intent = new Intent("com.wonderful.myfirstcode.MY_BROADCAST");
// 發(fā)送標準廣播
//sendBroadcast(intent);
// 發(fā)送有序廣播
sendOrderedBroadcast(intent, null);
}
});
. . .
}
. . .
}
發(fā)送有序廣播 sendOrderedBroadcast()
方法接收兩個參數(shù)蚤假,第一個是 Intent
栏饮,第二個是與權限相關的字符串,在這傳 null
就行了磷仰。當然現(xiàn)在運行程序點擊按鈕兩個應用程序還是會收到廣播袍嬉,接下來還需要修改 AndroidManifest.xml
文件中的標簽<receiver>
中的代碼,設定廣播接收器的先后順序:
<receiver
android:name=".chapter5.MyBroadcastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter android:priority="100">
<action android:name="com.wonderful.myfirstcode.MY_BROADCAST" />
</intent-filter>
</receiver>
上述代碼灶平,通過 android:priority
屬性給廣播接收器設置了優(yōu)先級伺通,優(yōu)先級比較高的廣播接收器就可以先收到廣播。把 MyBroadcastReceiver
的優(yōu)先級設成了 100民逼,保證它一定會在 AnotherBroadcastReceiver
之前收到廣播泵殴。
接下來涮帘,修改 MyBroadcastReceiver
中的代碼拼苍,設置是否允許廣播繼續(xù)傳遞。在 onReceive()
方法中調用 abortBroadcast()
方法,表示將這條廣播截斷疮鲫,后面的廣播接收器將無法再接收到這條廣播吆你。如下:
public class MyBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ToastUtils.showShort("收到自定義廣播");
// 將這條廣播攔截
abortBroadcast();
}
}
現(xiàn)在重新運行程序,就只有 MyBroadcastReceiver
可以接收到廣播彈提示信息了俊犯。
5.4 使用本地廣播
本地廣播只能夠在應用程序的內部進行傳遞妇多,并且廣播接收器也只能接收來自本應用程序發(fā)出的廣播。本地廣播的用法并不復雜燕侠,主要使用了一個 LocalBroadcastManager
來對廣播進行管理者祖,并提供了發(fā)送廣播和注冊廣播接收器的方法。
通過具體的實例來嘗試一下它的用法绢彤,修改 Activity
中的代碼:
public class BroadcastActivity extends AppCompatActivity {
private IntentFilter intentFilter;
private LocalReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
// 獲取實例
localBroadcastManager = LocalBroadcastManager.getInstance(this);
Button btn_send_broadcast = (Button) findViewById(R.id.btn_send_broadcast);
btn_send_broadcast.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
// 構建 Intent 對象
Intent intent = new Intent("com.wonderful.myfirstcode.LOCAL_BROADCAST");
// 發(fā)送有序廣播
localBroadcastManager.sendBroadcast(intent);
}
});
// 創(chuàng)建 IntentFilter 實例
intentFilter = new IntentFilter();
// 添加廣播值
intentFilter.addAction("com.wonderful.myfirstcode.LOCAL_BROADCAST");
// 創(chuàng)建 LocalReceiver 實例
localReceiver = new LocalReceiver();
// 注冊本地廣播監(jiān)聽器
localBroadcastManager.registerReceiver(localReceiver,intentFilter);
}
@Override
protected void onDestroy() {
super.onDestroy();
// 取消注冊
localBroadcastManager.unregisterReceiver(localReceiver);
}
/**
* 本地廣播接收器
*/
class LocalReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
ToastUtils.showShort("收到本地廣播");
}
}
}
基本上就和前面的動態(tài)注冊廣播接收器以及發(fā)送廣播的代碼是一樣七问。
??運行效果如下:
另外還有一點需要說明,本地廣播是無法通過靜態(tài)注冊的方式來接收的茫舶。
最后盤點一下使用本地廣播的優(yōu)勢:
可以明確知道正在發(fā)送的廣播不會離開我們的程序械巡,不需要擔心機密數(shù)據(jù)泄漏的問題。
其他的程序無法將廣播發(fā)送到我們程序的內部饶氏,不需要擔心會有安全漏洞的隱患讥耗。
發(fā)送本地廣播比起發(fā)送系統(tǒng)全局廣播將會更加高效。
5.5 廣播的最佳實踐——實現(xiàn)強制下線功能
又到了實戰(zhàn)環(huán)節(jié)了疹启。此次的需求是:強制下線后在界面上彈出一個對話框古程,讓用戶無法進行任何其他操作,必須要點擊對話框中的確定按鈕皮仁, 然后回到登錄界面籍琳。
借助本次所學的廣播知識,可以輕松實現(xiàn)這一功能贷祈。
首先趋急,創(chuàng)建一個 ActivityCollector
類用于管理所有的活動:
/**
* 活動管理器
* Created by KXwon on 2016/12/9.
*/
public class ActivityCollector {
// 通過一個List來緩存活動
public static List<Activity> activities = new ArrayList<Activity>();
/**
* 用于向List中添加一個活動
* @param activity
*/
public static void addActivity(Activity activity) {
activities.add(activity);
}
/**
* 用于從List中移除活動
* @param activity
*/
public static void removeActivity(Activity activity) {
activities.remove(activity);
}
/**
* 將List中存儲的活動全部銷毀掉
*/
public static void finishAll() {
for (Activity activity : activities) {
if (!activity.isFinishing()) {
activity.finish();
}
}
}
}
然后創(chuàng)建 BaseActivity
類作為所有活動的父類(忽略一些不必要的內容,主要看 ActivityCollector
相關的):
/**
* 基類
* Created by KXwon on 2016/12/9.
*/
public abstract class BaseActivity extends AppCompatActivity {
protected Context mContext;
protected Unbinder mBinder;
/**
* 初始化布局id
* @return 布局id
*/
protected abstract int initLayoutId();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(initLayoutId());
Log.d("BaseActivity", getClass().getSimpleName());// 知曉當前是在哪一個活動
ActivityCollector.addActivity(this);// 將當前正在創(chuàng)建的活動添加到活動管理期里
mContext = this;
mBinder = ButterKnife.bind(this);
}
@Override
protected void onDestroy() {
// 取消綁定
mBinder.unbind();
super.onDestroy();
// 將一個馬上要銷毀的活動從管理器里移除
ActivityCollector.removeActivity(this);
}
}
接下來創(chuàng)建一個登錄界面势誊,新建 LoginActivity
呜达,編輯 activity_login.xml
如下:
<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:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center"
android:textSize="18sp"
android:text="賬號:"/>
<EditText
android:id="@+id/et_account"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="60dp">
<TextView
android:layout_width="90dp"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:gravity="center"
android:textSize="18sp"
android:text="密碼:"/>
<EditText
android:id="@+id/et_password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"/>
</LinearLayout>
<Button
android:id="@+id/btn_login"
android:layout_width="match_parent"
android:layout_height="60dp"
android:layout_margin="10dp"
android:text="登錄"/>
</LinearLayout>
接著修改 LoginActivity 中的代碼:
public class LoginActivity extends BaseActivity {
private EditText et_account, et_password;
private Button btn_login;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
et_account = (EditText) findViewById(R.id.et_account);
et_password = (EditText) findViewById(R.id.et_password);
btn_login = (Button) findViewById(R.id.btn_login);
btn_login.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
String account = et_account.getText().toString();
String password = et_password.getText().toString();
// 若賬號是 wonderful 且密碼是 123456,就認為登錄成功
if (account.equals("wonderful") && password.equals("123456")){
// 登錄成功跳轉到主界面
IntentUtils.myIntent(LoginActivity.this,ForceOfflineActivity.class);
finish();
}else {
ToastUtils.showShort("賬號或密碼無效粟耻!");
}
}
});
}
@Override
protected int initLayoutId() {
return R.layout.activity_login;
}
}
登錄成功后跳轉到 ForceOfflineActivity
主界面查近,在主界面加入一個強制下線的功能即可,其布局 activity_force_offline.xml
代碼為:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="10dp">
<Button
android:id="@+id/btn_force_offline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="發(fā)送強制下線廣播"/>
</RelativeLayout>
只有一個按鈕挤忙,用于觸發(fā)強制下線功能霜威,然后修改 ForceOfflineActivity
中的代碼:
public class ForceOfflineActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Button btn_force_offline = (Button) findViewById(R.id.btn_force_offline);
btn_force_offline.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent("com.wonderful.myfirstcode.FORCE_OFFLINE");
// 發(fā)送強制下線廣播
sendBroadcast(intent);
}
});
}
@Override
protected int initLayoutId() {
return R.layout.activity_force_offline;
}
}
上述代碼,在按鈕的點擊事件里面發(fā)送了一條廣播册烈,廣播的值為 com.wonderful.myfirstcode.FORCE_OFFLINE
戈泼,這條廣播就是用于通知程序強制用戶下線的。也就是說強制用戶下線的邏輯并不是寫在 ForceOfflineActivity
里的,而是寫在接收這條廣播的廣播接收器里面大猛,這樣強制下線的功能就不會依附于任何的界面扭倾,不管是在程序的任何地方,只需要發(fā)出這樣一條廣播挽绩,就可以完成強制下線的操作了膛壹。
毫無疑問,要在 BaseActivity
中動態(tài)注冊一個廣播接收器唉堪,因為所有的活動都繼承 BaseActivity
的模聋,修改 BaseActivity
如下:
/**
* 基類
* Created by KXwon on 2016/12/9.
*/
public abstract class BaseActivity extends AppCompatActivity {
protected Context mContext;
protected Unbinder mBinder;
private ForceOfflineReceiver receiver;
/**
* 初始化布局id
* @return 布局id
*/
protected abstract int initLayoutId();
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(initLayoutId());
Log.d("BaseActivity", getClass().getSimpleName());// 知曉當前是在哪一個活動
ActivityCollector.addActivity(this);// 將當前正在創(chuàng)建的活動添加到活動管理期里
mContext = this;
mBinder = ButterKnife.bind(this);
}
@Override
protected void onResume() {
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.wonderful.myfirstcode.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() {
// 取消綁定
mBinder.unbind();
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("警告");
builder.setMessage("你已被下線,請重新登錄");
// 設置不可取消
builder.setCancelable(false);
// 設置點擊事件
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
// 銷毀所有活動
ActivityCollector.finishAll();
// 重新啟動 LoginActivity
IntentUtils.myIntent(context, LoginActivity.class);
}
});
builder.show();
}
}
}
上述代碼中唠亚,重寫了 onResume()
和 onPause()
這兩個生命周期的函數(shù)撬槽,然后分別在這兩個方法里注冊和取消注冊了 ForceOfflineReceiver
,之所以這樣寫而不是在 onCreate()
和 onDestroy()
方法里注冊和取消注冊是因為我們始終需要保證只有處于棧頂?shù)幕顒硬拍芙邮盏较戮€廣播趾撵,非棧頂活動不必要接收這條廣播侄柔,寫在 onResume()
和 onPause()
方法里很好的解決了這個問題,當活動失去棧頂位置時就會自動取消廣播接收器的注冊占调。
現(xiàn)在暂题,所有強制下線的邏輯處理完了,接下來運行程序究珊,首先進入登錄界面:
輸入正確的賬號和密碼后薪者,點擊登錄進入主界面:
這時點擊按鈕,就會發(fā)出一條強制下線的廣播剿涮,ForceOfflineReceiver
接收到這條廣播后會彈出一個提示對話框言津,這時就無法對其他界面的任何元素進行操作,只能點擊 OK 按鈕取试,重新回到登錄界面悬槽,如下:
關于廣播機制的學習就到這,下篇文章將進入持久化技術的學習瞬浓。