一.基本概念
强制下线功能功能应该算是比较常见的了,很多应用程序都具备这个功能,比如你的QQ号或者微信号在别处登录了,就会将你强制挤下线。只需要在界面上弹出一个对话框,让用户无法进行任何其他的操作,必须要点击对话框中的确定按钮,然后回到登录界面即可。可是这样就存在着一个问题,因为我们被通知需要强制下线时可能正处于任何一个界面,难道需要在每一个界面都编写一个弹出对话框的逻辑吗?如果真的是这样想那么思维就偏远了,我们完全可以借助所学的广播知识来实现这一个功能。
二.代码之旅
强制下线功能需要先关闭所有的活动,然后回到登录界面,代码如下所示:
package com.nyl.nativebroadcast; import android.app.Activity; import java.util.ArrayList; import java.util.List; 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(); } } } }
创建一个BaseActivity类作为所有活动的父类,代码如下所示:
package com.nyl.nativebroadcast; import android.app.Activity; import android.os.Bundle; public class BaseActivity extends Activity{ @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityCollector.addActivity(this); } @Override protected void onDestroy() { super.onDestroy(); ActivityCollector.removeActivity(this); } }
创建一个登录界面的布局,代码如下所示:
<?xml version="1.0" encoding="utf-8"?> <TableLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/activity_login" android:layout_width="match_parent" android:layout_height="match_parent" android:stretchColumns="1"> <TableRow> <TextView android:layout_height="wrap_content" android:text="账号:"/> <EditText android:id="@+id/etAccount" android:layout_height="wrap_content" android:hint="请输入账号"/> </TableRow> <TableRow> <TextView android:layout_height="wrap_content" android:text="密码:"/> <EditText android:id="@+id/etPassword" android:layout_height="wrap_content" android:inputType="textPassword"/> </TableRow> <TableRow> <Button android:id="@+id/btnLogin" android:layout_height="wrap_content" android:layout_span="2" android:text="登录"/> </TableRow> </TableLayout>
新建一个LoginActivity继承BaseActivity,代码如下所示:
package com.nyl.nativebroadcast; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class LoginActivity extends BaseActivity implements View.OnClickListener { private EditText etAccount; private EditText etPassword; private Button btnLogin; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); initView(); //初始化布局 } private void initView() { etAccount = (EditText) findViewById(R.id.etAccount); etPassword = (EditText) findViewById(R.id.etPassword); btnLogin = (Button) findViewById(R.id.btnLogin); btnLogin.setOnClickListener(this); } @Override public void onClick(View view) { //获取用户输入的账号,密码的数据 String account = etAccount.getText().toString(); String password = etPassword.getText().toString(); //如果账号是123且密码是123,就登录成功 if (account.equals("123") && password.equals("123")){ Intent intent = new Intent(LoginActivity.this,MainActivity.class); startActivity(intent); finish(); }else { Toast.makeText(LoginActivity.this,"账号或密码是无效的",Toast.LENGTH_SHORT).show(); } } }
同样在MainActivity继承BaseActivity,一个非常简单的MainActivity,不过多解释,代码如下所示:
package com.nyl.nativebroadcast; import android.content.Intent; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; public class MainActivity extends BaseActivity implements View.OnClickListener { private Button btnOffline; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); btnOffline = (Button) findViewById(R.id.btnOffline); btnOffline.setOnClickListener(this); } @Override public void onClick(View view) { Intent intent = new Intent("com.nyl.nativebroadcast.ForceOfflineReceiver"); sendBroadcast(intent); } }
创建一个广播接收器,代码如下所示:
package com.nyl.nativebroadcast; import android.app.AlertDialog; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.view.WindowManager; public class ForceOfflineReceiver extends BroadcastReceiver{ @Override public void onReceive(final Context context, Intent intent) { AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context); dialogBuilder.setTitle("警告"); dialogBuilder.setMessage("你被迫离线,请重新登录!"); dialogBuilder.setCancelable(false); dialogBuilder.setPositiveButton("确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { /** * 调用ActivityCollector的finishAll()方法来销毁掉所有的活动, * 并重新启动LoginActivity这个活动 */ ActivityCollector.finishAll();//销毁所以活动 Intent intent = new Intent(context,LoginActivity.class); /** * 在广播接收器里启动活动,因此一定要给Intent加入FLAG_ACTIVITY_NEW_TASK这个标准 */ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } }); AlertDialog alertDialog = dialogBuilder.create(); //需要设置AlertDialog的类型,保证在广播接收器中可以正常弹出 alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT); alertDialog.show(); } }
最后不要忘记在AndroidManifest.xml文件进行配置,代码如下所示:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.nyl.nativebroadcast"> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".LoginActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".MainActivity"></activity> <receiver android:name=".ForceOfflineReceiver"> <intent-filter> <action android:name="com.nyl.nativebroadcast.ForceOfflineReceiver"/> </intent-filter> </receiver> </application> </manifest>
好了,现在尝试运行一下程序吧,首先进入到登录界面,并可以在这里输入账号和密码,如下图:
如果输入的账号是:123,密码是123,点击登录按钮就会进入到程序的主界面,如下图:
这时点击一下发送强制用户下线的广播按钮,就会发出一条强制下线的广播,ForceOfflineReceiver里收到这条广播后会弹出一个对话框提示用户已被强制下线,如下图所示:
这时用户将无法再对界面的任何元素进行操作,只能点击OK按钮,然后回重新回到登录界面。这样,强制下线功能就已经完整的实现了。