Android入門之BroadCast模擬實(shí)現(xiàn)異地登錄事件發(fā)生后的主動(dòng)退出
簡介
隨著對BroadCast的越來越深入,我們今天要實(shí)現(xiàn)一個(gè)稍微復(fù)雜一點(diǎn)的BroadCast。即我們常用來有時(shí)APP打開時(shí)如果多個(gè)設(shè)備同時(shí)登錄一個(gè)帳號,而我們只允許一個(gè)設(shè)備登錄一個(gè)帳號時(shí),此時(shí)我們的APP會(huì)彈一個(gè)對話框如:您的賬號在別處登錄,請重新登陸!。

設(shè)計(jì)
要制作這樣的效果我們依舊是采用BroadCast,而且是一個(gè)自定義的Broadcast。此處需要:
1.自定義send一個(gè)broadcast;
2.注冊一個(gè)receiver,使得它監(jiān)聽我們這個(gè)自定義的broadcast;
3.在receiver的onReceive事件中,彈出一個(gè)“無窗體懸浮alert dialog”;
4.由于Android6及以后的相應(yīng)權(quán)限問題,你還要添加這個(gè)無窗體的懸浮alert dialog的權(quán)限;
5.又由于我們用的是SDK27及以后版本,因此光添加權(quán)限還沒有用,還要使用代碼喚出android關(guān)于這個(gè)app的一個(gè)“授權(quán)”系統(tǒng)窗口,在這個(gè)授權(quán)窗口內(nèi),用戶自己點(diǎn):allow后再進(jìn)行打開這個(gè)app操作,此時(shí)這個(gè)懸浮alert dialog才能正確被喚起否則當(dāng)這個(gè)alert dialog一旦被喚出你會(huì)得到一個(gè)permission denied 2038的錯(cuò)誤,然后Android App自動(dòng)退出;
好了,說了這么多我們來看代碼
全代碼
activity_main.xml
<?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/buttonLoginInOtherPlace"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="模擬異地登錄" />
</LinearLayout>
activity_login.xml
<?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="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="login_id:" />
<EditText
android:width="120dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="password:" />
<EditText
android:width="120dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="@+id/buttonLoginSubmit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="點(diǎn)一下代表登錄了" />
</LinearLayout>
</LinearLayout>以上定義了兩個(gè)窗體,運(yùn)行順序如下:
- activity_main先運(yùn)行,上面顯示一個(gè)“模擬異地登錄”按鈕,點(diǎn)一下會(huì)彈出一個(gè)alert dialog告訴你你現(xiàn)在要登出;
- 用戶點(diǎn)一下這個(gè)alert dialog上的【確定】,登錄出登錄,跳轉(zhuǎn)到一個(gè)登錄的activity_login界面;
- 在這個(gè)activity_login界面直接點(diǎn)【登錄】又登進(jìn)activity_main
先來看我們的Receiver,它接受來自activity_main的【模擬異地登錄】按鈕發(fā)送過來的broad cast。
BroadCastReceiver.java
package org.mk.android.demo.broadcast;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
public class BroadCastReceiver extends BroadcastReceiver {
private final String TAG = "BroadCastWithActivity";
@Override
public void onReceive(final Context context, Intent intent) {
Log.i(TAG, "receive broadcast->" + intent.getAction());
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
dialogBuilder.setTitle("警告:");
dialogBuilder.setMessage("您的賬號在別處登錄,請重新登陸!");
dialogBuilder.setCancelable(false);
dialogBuilder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCollector.getInstance().finishAll();
Intent intent = new Intent(context, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
AlertDialog alertDialog = dialogBuilder.create();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
alertDialog.show();
}
}接著,我們來看AndroidManifest.xml文件中的注冊以及相應(yīng)的靜態(tài)權(quán)限申請(這個(gè)對話框除了靜態(tài)權(quán)限還需要代碼在彈出對話框前申請動(dòng)態(tài)權(quán)限,這塊代碼我們寫在了MainActivity.java里的)。
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" />
<application
android:allowBackup="true"
android:dataExtractionRules="@xml/data_extraction_rules"
android:fullBackupContent="@xml/backup_rules"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DemoBroadCastWithActivity"
tools:targetApi="31">
<activity
android:name=".LoginActivity"
android:exported="false">
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<activity
android:name=".MainActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<meta-data
android:name="android.app.lib_name"
android:value="" />
</activity>
<receiver android:name=".BroadCastReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
<intent-filter>
<action android:name="ANDROID.INTENT.ACTION.MEDIA_MOUNTED"/>
<action android:name="ANDROID.INTENT.ACTION.MEDIA_UNMOUNTED"/>
<data android:scheme="file"/>
</intent-filter>
</receiver>
</application>
</manifest>接著我們來看我們的BroadCastReceiver寫法。
BroadCastReceiver.java
package org.mk.android.demo.broadcast;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Build;
import android.provider.Settings;
import android.util.Log;
import android.view.Window;
import android.view.WindowManager;
public class BroadCastReceiver extends BroadcastReceiver {
private final String TAG = "BroadCastWithActivity";
private static final String BROADCAST_ACTON = "org.mk.android.demo.broadcast";
@Override
public void onReceive(final Context context, Intent intent) {
if(intent.getAction().equals(BROADCAST_ACTON)) {
Log.i(TAG, "receive broadcast->" + intent.getAction());
AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
dialogBuilder.setTitle("警告:");
dialogBuilder.setMessage("您的賬號在別處登錄,請重新登陸!");
dialogBuilder.setCancelable(false);
dialogBuilder.setPositiveButton("確定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
ActivityCollector.getInstance().finishAll();
Intent intent = new Intent(context, LoginActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
}
});
AlertDialog alertDialog = dialogBuilder.create();
alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
alertDialog.show();
}
}
}我們可以看到,它里面定義了一個(gè)alert dialog,這個(gè)dialog在彈出時(shí)沒有context因此我們把它叫作無activity(窗體)依托dialog,因此這種dialog是必須要申請權(quán)限的,這是Android的規(guī)定。然后這個(gè)alert dialog有一個(gè)【確定】按鈕,點(diǎn)一下這個(gè)【確定】按鈕,就會(huì)以startActivity的方式再次打開activity_main界面,此處我們需要注意的是,這個(gè)startActivity里的intent的類型必須為Intent.FLAG_ACTIVITY_NEW_TASK),否則你死活從這個(gè)登錄界面跳不回activity_main的界面了。
接著看來MainActivity以及里面發(fā)生消息的部分(含代碼動(dòng)態(tài)申請Android權(quán)限)。
MainActivity.java
package org.mk.android.demo.broadcast;
import androidx.appcompat.app.AppCompatActivity;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
public class MainActivity extends BaseActivity {
private BroadCastReceiver localReceiver;
private LocalBroadcastManager localBroadcastManager;
private IntentFilter intentFilter;
private static final String BROADCAST_ACTON = "org.mk.android.demo.broadcast";
private final String TAG = "BroadCastWithActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Button buttonLoginInOtherPlace = (Button) findViewById(R.id.buttonLoginInOtherPlace);
localBroadcastManager = LocalBroadcastManager.getInstance(this);
//初始化廣播接收者,設(shè)置過濾器
localReceiver = new BroadCastReceiver();
intentFilter = new IntentFilter();
intentFilter.addAction(BROADCAST_ACTON);
localBroadcastManager.registerReceiver(localReceiver, intentFilter);
buttonLoginInOtherPlace.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (!Settings.canDrawOverlays(MainActivity.this)) {
Intent mintent = new Intent();
mintent.setAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(mintent);
}
Log.i(TAG, ">>>>>>MainActivity->onClick");
Intent intent = new Intent(BROADCAST_ACTON);
localBroadcastManager.sendBroadcast(intent);
}
});
}
@Override
protected void onDestroy() {
super.onDestroy();
localBroadcastManager.unregisterReceiver(localReceiver);
}
}這邊核心注意點(diǎn):
代碼動(dòng)代申請權(quán)限
if (!Settings.canDrawOverlays(MainActivity.this)) {
Intent mintent = new Intent();
mintent.setAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(mintent);
}
代碼運(yùn)行到這,Android會(huì)打開一個(gè)該APP相應(yīng)的系統(tǒng)權(quán)限對話框


然后把這邊的Allow手動(dòng)啟用。
接著我們重新運(yùn)行這個(gè)APP,效果如下。
運(yùn)行效果

點(diǎn)擊【確定】登出activity_main切換到activity_login

在這個(gè)界面點(diǎn)擊【點(diǎn)一下代表登錄了】按鈕,再次回到activity_main

到此這篇關(guān)于Android入門之BroadCast模擬實(shí)現(xiàn)異地登錄事件發(fā)生后的主動(dòng)退出的文章就介紹到這了,更多相關(guān)Android BroadCast異地登錄事件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Android 2d游戲開發(fā)之貪吃蛇基于surfaceview
這篇文章主要介紹了Android 2d游戲開發(fā)基于surfaceview的貪吃蛇,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-09-09
Android?Camera1實(shí)現(xiàn)預(yù)覽框顯示
這篇文章主要為大家詳細(xì)介紹了Android?Camera1實(shí)現(xiàn)預(yù)覽框顯示,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-05-05
android開發(fā)實(shí)踐之ndk編譯命令簡單示例
這篇文章主要給大家介紹了在android中ndk編譯命令使用的相關(guān)資料,文中詳細(xì)介紹了ndk-build命令行參數(shù),并通過簡單的示例代碼給大家介紹了如何編寫 .c 文件,需要的朋友可以參考借鑒,下面來一起看看吧。2017-06-06
Android實(shí)現(xiàn)布局動(dòng)畫和共享動(dòng)畫的結(jié)合效果
今天給大家?guī)砟軌蛱嵘脩趔w驗(yàn)感的交互動(dòng)畫,使用起來非常簡單,體驗(yàn)效果非常贊,其中僅使用到布局動(dòng)畫和共享動(dòng)畫,文章通過代碼示例介紹的非常詳細(xì),感興趣的同學(xué)可以自己動(dòng)手試一試2023-09-09
HttpClient通過Post上傳文件的實(shí)例代碼
這篇文章主要介紹了HttpClient通過Post上傳文件的實(shí)例代碼的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-08-08
Android天氣預(yù)報(bào)之基于HttpGet對象解析天氣數(shù)據(jù)的方法
這篇文章主要介紹了Android天氣預(yù)報(bào)之基于HttpGet對象解析天氣數(shù)據(jù)的方法,非常實(shí)用的功能,需要的朋友可以參考下2014-08-08

