網站首頁 編程語言 正文
簡介
隨著對BroadCast的越來越深入,我們今天要實現一個稍微復雜一點的BroadCast。即我們常用來有時APP打開時如果多個設備同時登錄一個帳號,而我們只允許一個設備登錄一個帳號時,此時我們的APP會彈一個對話框如:您的賬號在別處登錄,請重新登陸!。
設計
要制作這樣的效果我們依舊是采用BroadCast,而且是一個自定義的Broadcast。此處需要:
1.自定義send一個broadcast;
2.注冊一個receiver,使得它監聽我們這個自定義的broadcast;
3.在receiver的onReceive事件中,彈出一個“無窗體懸浮alert dialog”;
4.由于Android6及以后的相應權限問題,你還要添加這個無窗體的懸浮alert dialog的權限;
5.又由于我們用的是SDK27及以后版本,因此光添加權限還沒有用,還要使用代碼喚出android關于這個app的一個“授權”系統窗口,在這個授權窗口內,用戶自己點:allow后再進行打開這個app操作,此時這個懸浮alert dialog才能正確被喚起否則當這個alert dialog一旦被喚出你會得到一個permission denied 2038的錯誤,然后Android App自動退出;
好了,說了這么多我們來看代碼
全代碼
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="點一下代表登錄了" /> </LinearLayout> </LinearLayout>
以上定義了兩個窗體,運行順序如下:
- activity_main先運行,上面顯示一個“模擬異地登錄”按鈕,點一下會彈出一個alert dialog告訴你你現在要登出;
- 用戶點一下這個alert dialog上的【確定】,登錄出登錄,跳轉到一個登錄的activity_login界面;
- 在這個activity_login界面直接點【登錄】又登進activity_main
先來看我們的Receiver,它接受來自activity_main的【模擬異地登錄】按鈕發送過來的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文件中的注冊以及相應的靜態權限申請(這個對話框除了靜態權限還需要代碼在彈出對話框前申請動態權限,這塊代碼我們寫在了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();
}
}
}
我們可以看到,它里面定義了一個alert dialog,這個dialog在彈出時沒有context因此我們把它叫作無activity(窗體)依托dialog,因此這種dialog是必須要申請權限的,這是Android的規定。然后這個alert dialog有一個【確定】按鈕,點一下這個【確定】按鈕,就會以startActivity的方式再次打開activity_main界面,此處我們需要注意的是,這個startActivity里的intent的類型必須為Intent.FLAG_ACTIVITY_NEW_TASK),否則你死活從這個登錄界面跳不回activity_main的界面了。
接著看來MainActivity以及里面發生消息的部分(含代碼動態申請Android權限)。
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);
//初始化廣播接收者,設置過濾器
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);
}
}
這邊核心注意點:
代碼動代申請權限
if (!Settings.canDrawOverlays(MainActivity.this)) {
Intent mintent = new Intent();
mintent.setAction(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);
startActivity(mintent);
}
代碼運行到這,Android會打開一個該APP相應的系統權限對話框
然后把這邊的Allow手動啟用。
接著我們重新運行這個APP,效果如下。
運行效果
點擊【確定】登出activity_main切換到activity_login
在這個界面點擊【點一下代表登錄了】按鈕,再次回到activity_main
原文鏈接:https://blog.csdn.net/lifetragedy/article/details/128308590
相關推薦
- 2022-07-29 C#?中的多態底層虛方法調用詳情_C#教程
- 2022-12-09 PyTorch中關于tensor.repeat()的使用_python
- 2022-06-02 C語言深入淺出解析二叉樹_C 語言
- 2022-04-25 在?Python?中進行?One-Hot?編碼_python
- 2022-07-01 Python自動操作Excel文件的方法詳解_python
- 2022-12-03 C++時間函數整理詳解_C 語言
- 2022-11-05 Android開發RecyclerView實現折線圖效果_Android
- 2022-09-17 python?Pandas之DataFrame索引及選取數據_python
- 最近更新
-
- 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同步修改后的遠程分支