一、前言
假设有以下需求:你的某个账号在别处登录,你将强制下线。
普通的思路是:在每个页面都设置一个弹出框,让用户无法操作,必须点击对话框中的确定按钮,然后回到登录界面。
但是这样存在个问题:每个页面都编写一个弹出框,会很麻烦。
广播可以轻松的实现这一功能,下面实现。
效果如下:
二、代码实现
新建一个BroadcastBestPractice项目。
强制下线需要关闭所有的活动,然后回到登录界面。
所以首先实现关闭所有活动的功能。
1、关闭所有活动
创建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();
}
}
activities.clear();
}
}
然后创建BaseActivity类作为所有活动的父类,代码如下:
public class BaseActivity extends AppCompatActivity {
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}
protected void onDestroy(){
super.onDestroy();
ActivityCollector.removeActivity(this);
}
}
2、登录界面活动
首先创建一个LoginActivity活动。
编辑布局文件activity_login.xml,代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http:///apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<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:textSize="18sp"
android:text="账号:"/>
<EditText
android:id="@+id/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:textSize="18sp"
android:text="密码:"/>
<EditText
android:id="@+id/password"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
android:inputType="textPassword"/>
</LinearLayout>
<Button
android:id="@+id/login"
android:layout_width="match_parent"
android:layout_height="60dp"
android:text="登录"/>
</LinearLayout>
3、登录功能实现
修改LoginActivity类的代码,如下:
public class LoginActivity extends BaseActivity {
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 view) {
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, "账号或密码错误", Toast.LENGTH_SHORT).show();
}
}
});
}
}
4、强制下线按钮
修改activity_main.xml代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http:///apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/force_offline"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="强制下线"/>
</LinearLayout>
修改MainActivity代码,如下:
在按钮的点击事件里发送了一条广播,用于通知程序控制用户下线,强制用户下线的逻辑写在接收这条广播的广播接收器里。
那么在哪里创建一个广播接收器来接收这条广播?因为我们需要弹出对话框,因此使用动态注册一个广播接收器,在BaseActivity类里,因为所有活动继承这个类。
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 view) {
Intent intent = new Intent("com.example.broadcastbestpractice.FORCE_OFFLINE");
sendBroadcast(intent);
}
});
}
}
5、动态注册广播接收器
修改BaseActivity代码如下:
需要始终保证处于栈顶的活动才能接收到这条广播的强制下线,非栈顶活动不应该没必要去接收这条广播,所以在onResume()和onPause()方法里注册和取消注册广播接收器。
当一个活动失去栈顶位置时自动取消广播接收器的注册。
public class BaseActivity extends AppCompatActivity {
private ForceOfflineReceiver receiver;
protected void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
ActivityCollector.addActivity(this);
}
protected void onDestroy(){
super.onDestroy();
ActivityCollector.removeActivity(this);
}
protected void onResume(){
super.onResume();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE");
receiver = new ForceOfflineReceiver();
registerReceiver(receiver,intentFilter);
}
protected void onPause(){
super.onPause();
if(receiver != null){
unregisterReceiver(receiver);
receiver = null;
}
}
class ForceOfflineReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
AlertDialog.Builder builder = new AlertDialog.Builder(context);
builder.setTitle("警告");
builder.setMessage("你被强制下线,请重新登录");
builder.setCancelable(false);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
ActivityCollector.finishAll();
Intent intent = new Intent(context,LoginActivity.class);
context.startActivity(intent);
}
});
builder.show();
}
}
}
最后不要忘记修改AndroidManifest.xml文件,LoginActivity作为首页。
最后演示一下: