"First Line of Code" broadcast

 

10. Broadcast Receiver

 

  Broadcasting in Android can be mainly divided into two types, standard broadcasting and ordered broadcasting .

 

  Normal broadcasts:

  It is a completely asynchronous broadcast. After the broadcast is sent, all broadcast receivers will receive the broadcast message at almost the same time , so there is no order between them.

 

  Ordered broadcasts:

  It is a broadcast that is executed synchronously. After the broadcast is sent, only one broadcast receiver can receive the broadcast message at the same time . When the logic in the broadcast receiver is executed, the broadcast will continue to be delivered. Therefore, the broadcast receivers at this time are in sequence. The broadcast receiver with high priority can receive the broadcast message first, and the previous broadcast receiver can also truncate the broadcast being delivered.

 

  There are generally two ways to register broadcasting, registering in code and registering in AndroidManifest.xml , the former is also called dynamic registration , and the latter is also called static registration .

 

Create a broadcast receiver:

  Create a new class, let it inherit from BroadcastReceiver , and override the onReceive() method of the parent class. In this way, when a broadcast arrives, the onReceive() method will be executed

 

  Dynamic registration:

    Because the logic is written in onCreate(), the broadcast must be received after the program starts

    Dynamically registered broadcast receivers must be unregistered . Here we do this by calling the unregisterReceiver() method in the onDestroy() method.

 

class NetworkChangeReceiver extends BroadcastReceiver {

			@Override
			public void onReceive(Context context, Intent intent) {
				Toast.makeText(context, "network changes",Toast.LENGTH_SHORT).show();
			}
		}

 

// MainActivity:

		protected void onCreate(Bundle savedInstanceState) {
			...
			//When the network state changes, the system sends a broadcast with the value android.net.conn.CONNECTIVITY_CHANGE

			intentFilter = new IntentFilter();	
intentFilter.addAction("android.net.conn.CONNECTIVITY_CHANGE");

			//receiver
			networkChangeReceiver = new NetworkChangeReceiver();
			registerReceiver(networkChangeReceiver, intentFilter);
		}
			

		@Override
		protected void onDestroy() {
			super.onDestroy ();
			unregisterReceiver(networkChangeReceiver);
		}

		class NetworkChangeReceiver extends BroadcastReceiver {

		}

 Open the AndroidManifest.xml file and add the following permissions to it

  

<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>

  

Static registration:

  Allows the program to receive broadcasts without starting

 

    Create a new BootCompleteReceiver that inherits from BroadcastReceiver:

 

public class BootCompleteReceiver extends BroadcastReceiver {

			public void onReceive(Context context, Intent intent) {
				Toast.makeText(context, "Boot Complete", Toast.LENGTH_LONG).show();
			}
		}

 In AndroidManifest.xml add:

  

<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

		<application
			……			

			<receiver android:name=".BootCompleteReceiver" >
				<intent-filter>
					<action android:name="android.intent.action.BOOT_COMPLETED" />
				</intent-filter>
			</receiver>
		</application>

 

 

Send custom broadcast

 

Send a standard broadcast:

  1. Create a new broadcast receiver

  Create a new MyBroadcastReceiver that inherits from BroadcastReceiver

 

  2. Register the broadcast receiver in AndroidManifest.xml

 

<receiver android:name=".MyBroadcastReceiver">

		<intent-filter>
			<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
		</intent-filter>
	</receiver>

  

  3. Define the button to send the broadcast

 

public void onClick(View v) {
		Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
		sendBroadcast (intent);
	}

 

 

Send an ordered broadcast:

  1~2 are the same as standard broadcast

  4、

Intent intent = new Intent("com.example.broadcasttest.MY_BROADCAST");
sendOrderedBroadcast (intent, null);

 

  The sendOrderedBroadcast() method receives two parameters. The first parameter is still Intent, and the second parameter is a string related to permissions. Here, just pass in null.

 

  The android:priority attribute sets the priority for the broadcast receiver, and the broadcast receiver with a higher priority can receive the broadcast first.

<receiver android:name=".MyBroadcastReceiver">

		<intent-filter android:priority="100" >
			<action android:name="com.example.broadcasttest.MY_BROADCAST"/>
		</intent-filter>
	</receiver>

 The abortBroadcast() method means to truncate this broadcast and use it in the broadcast receiver

 

Use local broadcast:

  前面我们发送和接收的广播全部都是属于系统全局广播,

  即发出的广播可以被其他任何的任何应用程序接收到,并且我们也可以接收来自于其他任何应用程序的广播

 

  本地广播的用法并不复杂,主要就是使用了一个 LocalBroadcastManager 来对广播进行管理

 

1、接收器

class LocalReceiver extends BroadcastReceiver {

		@Override
		public void onReceive(Context context, Intent intent) {
			Toast.makeText(context, "received local broadcast",Toast.LENGTH_SHORT).show();
		}
	}

 

2、

public class MainActivity extends Activity {

		private IntentFilter intentFilter;
		private LocalReceiver localReceiver;
		private LocalBroadcastManager localBroadcastManager;
		

		@Override
		protected void onCreate(Bundle savedInstanceState) {
			。。。
			//获取localBroadcastManager
			localBroadcastManager = LocalBroadcastManager.getInstance(this);
			Button button = (Button) findViewById(R.id.button);
			button.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				 // 发送本地广播
				Intent intent = new Intent("com.example.broadcasttest.LOCAL_BROADCAST");
				localBroadcastManager.sendBroadcast(intent);
				}
			});
	

			intentFilter = new IntentFilter();
			intentFilter.addAction("com.example.broadcasttest.LOCAL_BROADCAST");
			localReceiver = new LocalReceiver();
			localBroadcastManager.registerReceiver(localReceiver, intentFilter);

		}			

		@Override
		protected void onDestroy() {
			super.onDestroy();
			localBroadcastManager.unregisterReceiver(localReceiver);
		}

 

广播的最佳实践——实现强制下线功能

原理:

点击强制下线按钮,发送一条”强制下线“的广播,在广播接收器里弹出一个不可取消的对话框,点击对话框确定按钮,调用 ActivityCollector 的 finishAll()方法来销毁掉所有活动,并重新启动 LoginActivity 这个活动

 

强制用户下线的逻辑并不是写在 MainActivity 里的,而是应该写在接收这条广播的广播接收器里面这样强制下线的功能就不会依附于任何的界面,不管是在程序的任何地方,只需要发出这样一条广播,就可以完成强制下线的操作了。

 

注意:

由于我们是在广播接收器里启动活动的,因此一定要给Intent 加入 FLAG_ACTIVITY_NEW_TASK 这个标志。

还需要把对话框的类型设为 TYPE_SYSTEM_ALERT,不然它将无法在广播接收器里弹出

 

1、发送广播:

public void onClick(View v) {
      Intent intent = new Intent("com.example.broadcastbestpractice.FORCE_OFFLINE ");
      sendBroadcast(intent);
}

  

2、接收广播:

public class ForceOfflineReceiver extends BroadcastReceiver {

    @Override
    public void onReceive(final Context context, Intent intent) {
        Toast.makeText(context, "received in ForceOfflineReceiver", Toast.LENGTH_SHORT).show();


        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
        dialogBuilder.setTitle("Warning");
        dialogBuilder.setMessage("You are forced to be offline. Please try to login again.");
        dialogBuilder.setCancelable(false);

        //点击对话框OK
        dialogBuilder.setPositiveButton("OK",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        ActivityCollector.finishAll(); // 销毁所有活动
                        Intent intent = new Intent(context,MainActivity.class);
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        context.startActivity(intent); // 重新启动LoginActivity
                    }
                });

        AlertDialog alertDialog = dialogBuilder.create();
        // 需要设置AlertDialog的类型,保证在广播接收器中可以正常弹出
        alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);
        alertDialog.show();

       // context.unregisterReceiver(this);
    }
}

 

3、注册广播接收器,声明权限 android.permission.SYSTEM_ALERT_WINDOW 

 

问题:

1、Broadcast的onReceive方法中弹出AlertDialog

 

使用静态注册广播,只能弹出System Alert类型的Dialog。但google在 6.0加入了运行时权限的概念,需要在java代码中进行动态申请。为了防止旧的应用程序崩溃,只对targetSDK为23及以上的程序使用新的权限机制。 

相应的解决方法有如下几种。 

第一种方式是:targetSDK设为23以下就可以规避问题。 

第二种方式是:设置里面给了这个调试应用【允许悬浮窗】 但是得手动的打开(我是没有找到这个悬浮窗到底在哪里)。 

第三种方式是:使用无需权限显示悬浮窗。

 

a 修改广播接收类中的import包 将

import android.support.v7.app.AlertDialog;

修改为:

import android.app.AlertDialog;

 

b 修改AlertDialog的弹窗类型为:TYPE_TOAST 将

alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

修改为:

alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_TOAST);

这样编译运行就可以正常弹出AlertDialog了。

 

2、在广播中弹出对话框与在Activiity中弹出对话框有所不同,在Activiity中弹出对话框,我们需要用到当前Activiity的Context,而在广播中并没有,如果一定要在广播中弹出一个对话框,我需要定义这个对话框是一个系统级别的。

首先需要有弹出系统对话框的权限

<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />

在show()之前,要先设置Dialog的类型为TYPE_SYSTEM_ALERT。

alertDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);

最后,最最重要的,AlertDialog要使用android.app.AlertDialog,不要用v7包下的Dialog,会报错。

 

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326015162&siteId=291194637