Android LocalBroadcast本地广播
经过前面几章节的学习,我们对 BroadcastReceiver
应该有非常深的了解,知晓了如何接收广播和如何发送广播,这已经满足我们大部分的需求了
但前面说的广播都是 全局广播,意味着我们 APP
发出的广播,其它 APP
都会接收到,
或者其它 APP 发送的广播,我们的 APP 也会接收到,这样容易引起一些安全性的问题
Android 提供了 本地广播 的机制,使用该机制发出的广播只会在 APP
内部传播,而且
广播接收者也只能收到本应用发出的广播
本地广播
本地广播 发出的广播只会在 APP
内部传播,而且
广播接收者也只能收到本应用发出的广播
本地广播无法通过静态注册方式来接受,相比起系统全局广播更加高效
使用流程
使用 LocalBroadcastManager
来管理广播
- 调用
LocalBroadcastManager.getInstance()
获得实例mLBM
- 调用
mLBM.registerReceiver()
注册广播 - 调用
mLBM.sendBroadcase()
发送广播 - 调用
mLBM.unregisterReceiver()
取消注册广播
注意事项
-
在广播中启动
Activity
的话需要为intent
加入FLAG_ACTIVITY_NEW_TASK
标记,不然会报错,因为需要一个栈来存放新打开的Activity
-
广播中弹出
AlertDialog
的话,需要设置对话框的类型为TYPE_SYSTEM_AERT
不然无法弹出
范例
我们写一个 demo 别处登录踢人下线 来演示下本地广播
像微信一样,正在运行的微信,如果我们用别的手机再次登陆自己的账号,前面这个是会提醒账户
在别的终端登录这样,然后把我们打开的所有 Activity
都关掉,然后回到登陆页面这样
-
创建一个 空的 Android 项目
cn.twle.android.LocalBroadcast
-
在
MainActivity.java
目录下创建文件ActivityManager.java
用来管理所有的Activity
package cn.twle.android.localbroadcast; import java.util.List; import java.util.ArrayList; import android.app.Activity; public class ActivityManager { private static List<Activity> activities = new ArrayList<Activity>(); 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(); } } } }
-
在
MainActivity.java
目录下创建文件MsBaseActivity.java
作为所有Activity
的基础类package cn.twle.android.localbroadcast; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; public class MsBaseActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ActivityManager.addActivity(this); } @Override protected void onDestroy() { super.onDestroy(); ActivityManager.removeActivity(this); } }
-
在
res/layout
目录下新建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:gravity="center_horizontal" android:padding="8dp" android:orientation="vertical" > <TextView android:text="用户名" android:layout_width="match_parent" android:layout_height="wrap_content" /> <EditText android:id="@+id/login_username" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="123" /> <TextView android:text="密 码" android:layout_width="match_parent" android:layout_height="wrap_content" /> <EditText android:id="@+id/login_passwd" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="123" /> <Button android:text="登录" android:id="@+id/btn_login" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
-
在
MainActivity.java
目录下创建文件LoginActivity.java
作为登录页面的Activity
package cn.twle.android.localbroadcast; import android.content.Intent; import android.content.SharedPreferences; import android.os.Bundle; import android.preference.PreferenceManager; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.Toast; public class LoginActivity extends MsBaseActivity implements View.OnClickListener{ private SharedPreferences pref; private SharedPreferences.Editor editor; private EditText login_username; private EditText login_passwd; private Button btn_login; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_login); pref = PreferenceManager.getDefaultSharedPreferences(this); bindViews(); } private void bindViews() { login_username = (EditText) findViewById(R.id.login_username); login_passwd = (EditText) findViewById(R.id.login_passwd); btn_login = (Button) findViewById(R.id.btn_login); btn_login.setOnClickListener(this); } @Override protected void onStart() { super.onStart(); if(!pref.getString("user","").equals("")){ login_username.setText(pref.getString("user","")); login_passwd.setText(pref.getString("pawd","")); } } @Override public void onClick(View v) { String user = login_username.getText().toString(); String pawd = login_passwd.getText().toString(); if(user.equals("123")&&pawd.equals("123")){ editor = pref.edit(); editor.putString("user", user); editor.putString("pawd", pawd); editor.commit(); Intent intent = new Intent(LoginActivity.this, MainActivity.class); startActivity(intent); Toast.makeText(LoginActivity.this,"哟,竟然蒙对了~",Toast.LENGTH_SHORT).show(); finish(); }else{ Toast.makeText(LoginActivity.this,"这么简单都输出,脑子呢?",Toast.LENGTH_SHORT).show(); } } }
-
在
MainActivity.java
目录下创建文件MsBroadcastReceiver.java
重写
onReceive()
并实现弹出对话框操作,以及启动登陆页面package cn.twle.android.localbroadcast; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.app.AlertDialog; import android.view.WindowManager; public class MsBroadcastReceiver 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 dialog, int which) { ActivityManager.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_SYSTEM_ALERT); alertDialog.show(); } }
-
修改
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:gravity="center_horizontal" android:orientation="vertical" > <Button android:text="发送登录信息" android:id="@+id/btn_send" android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
-
修改
MainActivity.java
package cn.twle.android.localbroadcast; import android.content.Intent; import android.content.IntentFilter; import android.os.Bundle; import android.support.v4.content.LocalBroadcastManager; import android.view.View; import android.widget.Button; public class MainActivity extends MsBaseActivity { private MsBroadcastReceiver localReceiver; private LocalBroadcastManager localBroadcastManager; private IntentFilter intentFilter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); localBroadcastManager = LocalBroadcastManager.getInstance(this); //初始化广播接收者,设置过滤器 localReceiver = new MsBroadcastReceiver(); intentFilter = new IntentFilter(); intentFilter.addAction("cn.twle.android.localbroadcast.LOGIN_OTHER"); localBroadcastManager.registerReceiver(localReceiver, intentFilter); Button btn_send = (Button) findViewById(R.id.btn_send); btn_send.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent("com.jay.mybcreceiver.LOGIN_OTHER"); localBroadcastManager.sendBroadcast(intent); } }); } @Override protected void onDestroy() { super.onDestroy(); localBroadcastManager.unregisterReceiver(localReceiver); } }
-
修改
AndroidManifest.xml
中加上系统对话框权限,注册Broadcast
和Activity
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.twle.android.localbroadcast"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".LoginActivity" android:theme="@style/Theme.AppCompat.Dialog" /> <receiver android:name=".MsBroadcastReceiver"> <intent-filter> <action android:name="cn.twle.android.localbroadcast.LOGIN_OTHER"/> </intent-filter> </receiver> </application> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> </manifest>
尝试运行,用户名和密码都是 "123"