ブロードキャストとは何ですか?
ブロードキャストは、プログラム コンポーネント間でメッセージを送信するメカニズムであり、ブロードキャストの内容はデータを運ぶインテントであり、ユーザー インターフェイスはありません。
同じ APP 内の異なるコンポーネントが送信され、異なる APP コンポーネント間でメッセージが送信されます。
デフォルトでは、ブロードキャスト レシーバーは UI スレッドで実行されます。
ブロードキャスト レシーバーのライフ サイクルは非常に短いです。ブロードキャスト レシーバーはブロードキャストの受信時に作成され、onReceive() メソッドの終了後に破棄されます。ブロードキャスト レシーバーで時間のかかる作業を行わないでください。そうしないと、アプリケーション応答なしエラー ダイアログ ボックスが表示されます。ブロードキャスト レシーバーが破壊されるとプロセスは空のプロセスになり、システムによって簡単に強制終了されるため、時間のかかる作業を行うためにブロードキャスト レシーバー内にサブスレッドを作成しないでください。長期的な仕事はサービスで行うのが最適です。
放送受信機
- 標準ブロードキャスト: 非同期実行。受信機は送信後ほぼ同時にブロードキャストを受信します。
- 秩序あるブロードキャスト: 同期実行。同時に受信できるのは 1 台の受信機のみです。受信機は、ロジックの実行後に停止するか、送信を継続するか、ブロードキャストの内容を変更するかを選択できます。
- スティッキー ブロードキャスト: スティッキー ブロードキャストの送信後、レシーバーが見つからない場合は永久に待機し、レシーバーは再構築時にブロードキャストを受信します。(重要な状態変化情報が永続化され、いつでも新しいブロードキャスト受信機にブロードキャストできるようにする)
- システムブロードキャスト: システムプログラムによって送信されるブロードキャストは標準ブロードキャストです。主に携帯電話の基本操作に関する内容です。
標準ブロードキャスト:標準ブロードキャストは、動的登録と静的登録の 2 つのタイプに分けられます。
静的ブロードキャスト登録
MyStaticReceiver クラスは非常に単純で、受信した情報を出力するだけです。
package com.hope.demo.broadcast;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import com.hxc.supreme.utils.ToastUtil;
public class MyStaticReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("MyStaticReceiver", "onReceive: "+intent.getStringExtra("info"));
}
}
マニフェストのコード ブロック:
<receiver
android:name=".broadcast.MyStaticReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="hopu"/>
</intent-filter>
</receiver>
次に、メイン インターフェイスにクリック ボタンがあり、レイアウト ファイルは非常にシンプルです。
public class BroadcastActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tvStaticBroadcast;
private TextView tvDynamicBroadcast;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
tvStaticBroadcast = findViewById(R.id.tv_static_broadcast);
tvDynamicBroadcast = findViewById(R.id.tv_dynamic_broadcast);
tvStaticBroadcast.setOnClickListener(this);
tvDynamicBroadcast.setOnClickListener(this);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.tv_static_broadcast:
sendBroadcast();
break;
case R.id.tv_dynamic_broadcast:
break;
}
}
private void sendBroadcast() {
Intent intent = new Intent();
intent.setAction("hopu");
intent.putExtra("info", "这是一条静态广播");
sendBroadcast(intent);
}
}
次に、logcat のログ出力を確認します。
MyStaticReceiver: onReceive: これは静的ブロードキャストです
ただし、Android 8.0 以降のシステムでは、静的ブロードキャストを受信できません。Google は、8.0 以降、効率を向上させるために、アプリを閉じた後にブロードキャストが続行されないように静的登録を削除し、メモリ リークを引き起こしたことを発見しました。現在、静的登録のブロードキャストではパッケージ名を指定する必要があります。!!
これは、8.0 以降、Google が静的登録を動的登録に置き換えることを公式に推奨していることを意味するため、パッケージ名を指定してそれが機能するかどうかを確認してみましょう。
このコードは、ブロードキャストの送信方法のみを変更します。
private void sendBroadcast() {
Intent intent = new Intent();
intent.setPackage(getPackageName());//Android8.0以上需指定包名
intent.setAction("hopu");
intent.putExtra("info", "这是一条静态广播");
sendBroadcast(intent);
}
logcat の出力ログを確認します。
MyStaticReceiver: onReceive: これは静的ブロードキャストです
事実はそれが可能であることを証明していますが、Google は動的登録の使用を推奨しているため、動的登録の使用方法を見てみましょう。
動的ブロードキャスト登録
public class BroadcastActivity extends AppCompatActivity implements View.OnClickListener {
private TextView tvStaticBroadcast;
private TextView tvDynamicBroadcast;
private DynamicReceiver dynamicReceiver;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_broadcast);
tvStaticBroadcast = findViewById(R.id.tv_static_broadcast);
tvDynamicBroadcast = findViewById(R.id.tv_dynamic_broadcast);
tvStaticBroadcast.setOnClickListener(this);
tvDynamicBroadcast.setOnClickListener(this);
dynamicReceiver = new DynamicReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("husanity");
registerReceiver(dynamicReceiver, intentFilter);
}
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.tv_static_broadcast:
sendBroadcast();
break;
case R.id.tv_dynamic_broadcast:
sendDynamicBroadcast();
break;
}
}
private void sendBroadcast() {
Intent intent = new Intent();
intent.setPackage(getPackageName());//Android8.0以上需指定包名
intent.setAction("hopu");
intent.putExtra("info", "这是一条静态广播");
sendBroadcast(intent);
}
private void sendDynamicBroadcast() {
Intent intent = new Intent();
intent.setAction("hopu");
intent.putExtra("extra", "这是一条动态广播");
sendBroadcast(intent);
}
class DynamicReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Log.i("BroadcastActivity", "onReceive: " + intent.getStringExtra("extra"));
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//onDestroy中需要反注册,用来优化内存空间避免内存泄漏
unregisterReceiver(dynamicReceiver);
}
}
logcat の印刷ログを確認してください。
BroadcastActivity: onReceive: これは動的ブロードキャストです
特定のケース
ネットワーク内で変更があったブロードキャストを受信するためにブロードキャスト受信機を動的に登録する
public class HomeActivity extends AppCompatActivity {
private NetWorkReceiver receiver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
//创建一个意图过滤器
IntentFilter filter = new IntentFilter();
//接收网络改变的action
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
receiver = new NetWorkReceiver();
//注册广播
this.registerReceiver(this.receiver, filter);
}
/*
* 取消注册
* */
@Override
protected void onDestroy() {
super.onDestroy();
this.unregisterReceiver(this.receiver);
}
public class NetWorkReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
ConnectivityManager connectivityManager = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
//如果当前有默认的网络就返回NetworkInfo 否则就返回 null
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
//因为可能是null 所以要先判断是否为空
if (networkInfo != null && networkInfo.isAvailable()) {
if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
Toast.makeText(context, "Wifi", Toast.LENGTH_SHORT).show();
} else if (networkInfo.getType() == ConnectivityManager.TYPE_MOBILE) {
Toast.makeText(context, "流量", Toast.LENGTH_SHORT).show();
}
} else {
Toast.makeText(context, "世界上最遥远的距离就是没有网", Toast.LENGTH_SHORT).show();
}
}
}
}
ブロードキャスト受信機を静的に登録してブートを実現
<!--注册我们的开机广播-->
<receiver
android:name=".MyBootComplatedReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
public class MyBootComplatedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
Intent gotoIntent = new Intent(context, RootComplatedActivity.class);
context.startActivity(gotoIntent);
}
}
秩序ある放送
Context.sendOrderedBroadcast を通じて送信すると、すべての受信者が順番に実行されます。BroadcastReceiver は、setResult 一連の関数を使用して結果を次の BroadcastReceiver に渡し、getResult 一連の関数を使用して前の BroadcastReceiver によって返された結果を取得し、一連の abort 関数を使用してシステムにブロードキャストを破棄させることができます。ブロードキャストを使用して、他の BroadcastReceiver にブロードキャストを送信しなくなります。インテントフィルターに android:priority 属性を設定することでレシーバーの優先度を設定できますが、同じ優先度を持つレシーバーの実行順序は不確かです。
例:
SMS 傍受: アプリのブロードキャスト レシーバーのレベルをシステムの元のレベルよりも高く設定し、受信後にブロードキャストを中断して、受信トレイで SMS が受信されないようにすることができます。
BroadCastReceiver のアプリケーション シナリオは何ですか?
APP内部メッセージ通信。
異なるAPP間のメッセージ通信。
システムからデバイス情報を受信します。
ブロードキャストの優先順位は、順序が乱れたブロードキャストに対しても機能しますか?
優先順位は順不同のブロードキャストに対して有効になります
動的登録の優先順位が高いのは誰ですか?
まず、優先順位を自分で設定します。次に、最初に登録した人が優先されます。
現在の放送受信機が受信している放送が秩序ある放送であるか乱れた放送であるかをどのように判断するのでしょうか?
onReceive で isOrderedBroadcast() を呼び出す
時間のかかる操作を BroadcastReceiver で実行できないのはなぜですか?
- 通常、BroadcastReceiver はメインスレッド内にあり、時間が 10 秒を超えると ANR エラーが報告されます。
- BroadcastReceiver はすぐに起動します。プロセス内にレシーバーが 1 つしかなく、時間のかかるサブスレッドが開かれている場合、システムは、onReceive が実行されてブロードキャスト レシーバーが破棄された後、それを空のプロセスとみなし、最初にそれを強制終了します。 。
- ブロードキャスト受信機が有効な独立スレッド (受信機のプロセスがマニフェストで設定されている) であり、時間のかかるタスクを実行するためにその中でサブスレッドが開かれている場合、メモリが不足した場合にも簡単にリサイクルされます。サブスレッド内のタスクを完了できません (2 など)。
ローカル放送
- ローカル ブロードキャストの送信者と受信者は両方とも同じに属します
APP
- グローバルブロードキャストと比較して、次の利点があります。
- それ以外は
APP
ローカル放送の対象外となるため、データ漏洩の心配はありません。- 他の人が
APP
現在のブロードキャストにAPP
ローカル ブロードキャストを送信することは 不可能なので、セキュリティ ホールがAPP
他人に悪用される心配はありません。- ローカル ブロードキャストは、システムを通じて配信されるグローバル ブロードキャストよりも効率的に配信されます。
Android v4
このクラスは APP のローカルブロードキャストを統一的に扱うためのパッケージで提供されておりLocalBroadcastManager
、利用方法はグローバルブロードキャストとほぼ同じですが、登録・登録解除ブロードキャスト受信機の呼び出しやブロードキャストの随時読み出しメソッドを送信する際に必要となる点が異なります。 クラスのメソッドで取得したインスタンスによって呼び出されますLocalBroadcastManager
。getInstance()
フォアグラウンド ブロードキャスト バックグラウンド ブロードキャスト?
フォアグラウンド ブロードキャストはフォアグラウンド キューに対応し、バックグラウンド ブロードキャストはバックグラウンド キューに対応します。ブロードキャストは、Intent.FLAG_RECEIVER_FOREGROUND プロパティを設定することでフォアグラウンド ブロードキャストとして定義できます。定義されていない場合は、デフォルトでバックグラウンド ブロードキャストが使用されます。フォアグラウンドのブロードキャスト タイムアウトは 10 秒、バックグラウンドは 60 秒です。
静的ブロードキャストと動的ブロードキャスト
- 静的ブロードキャスト: 実行中である限り
app
、常にブロードキャスト メッセージを受信します。- ダイナミックブロードキャスト:登録したコンポーネントが破壊されるとブロードキャストを受信できなくなります。