Erkundung der Ausstrahlung der vier Hauptkomponenten von Android

Inhaltsverzeichnis

1. Der Mechanismus des Rundfunks

2. Erkunden Sie den Rundfunk

1. Dynamische Registrierung

2. Statische Registrierung und Senden einer Standardsendung

3. Senden Sie eine ordnungsgemäße Sendung

3. Stellen Sie Fragen

erste Frage

zweite Frage

dritte Frage

4. Erkundungsfragen

erste Frage

zweite Frage

dritte Frage


Broadcasting ist eine gute Sache. Unser Programm kann Broadcasts senden und empfangen, um andere Programme über Neuigkeiten zu informieren oder Nachrichten von anderen Programmen zu empfangen.

1. Der Mechanismus des Rundfunks

Es gibt zwei Arten von Sendungen:

  1. Standardsendung

    Dies ist eine asynchrone Übertragung. Nachdem die Rundsendung ausgesendet wurde, können alle entsprechenden Rundsendungsempfänger die Rundsendungsnachricht empfangen. Solche Sendungen sind effizienter, können aber nach dem Senden nicht mehr abgefangen werden.

  2. geordnete Sendung

    Wie der Name schon sagt, wird diese Art von Broadcast sequentiell gesendet und ist ein synchroner Broadcast. Entsprechend der Reihenfolge, in der die Gewichte gesendet werden. Und das Programm, das die Sendung zuerst empfängt, kann die Sendung abschneiden, wodurch es für nachfolgende Empfänger unmöglich wird, sie zu empfangen.

Es gibt zwei Möglichkeiten, die Übertragung zu akzeptieren:

  1. dynamische Registrierung

    Auf diese Weise können wir Rundfunkempfänger jederzeit im Programm an- oder abmelden. Beispielsweise registrieren wir den Broadcast-Empfänger in onResume() von Activity und kündigen den Broadcast-Empfänger in onPause(). Dies hat den Vorteil, dass es sehr flexibel ist, aber die Einschränkung besteht darin, dass die Aktivität gestartet werden muss, bevor sie empfangen werden kann.

  2. statische Registrierung

    Wir können eine Klasse schreiben, die von BroadcastReceiver erbt, diesen Broadcast-Empfänger in AndroidManifest.xml registrieren und den zu akzeptierenden Broadcast-Typ angeben.

2. Erkunden Sie den Rundfunk

1. Dynamische Registrierung

Lassen Sie uns zuerst versuchen, eine dynamische Registrierung zu verwenden, um eine Sendung von einem System zu empfangen.

Erstellen Sie eine neue Aktivität und erstellen Sie eine innere Klasse darin:

    inner class TimeChangeReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            Toast.makeText(context, "the time has changed!", Toast.LENGTH_SHORT).show()
        }
    }

Diese Klasse erbt BroadcastReceiver, bei dem es sich um einen Broadcast-Empfänger handelt. Schreiben Sie dann die onReceive()-Methode neu und verarbeiten Sie die zu verarbeitende Logik, wenn der Broadcast empfangen wird.

Dann registrieren wir den Broadcast-Empfänger dynamisch in onCreate().

    lateinit var timeChangeReceiver: TimeChangeReceiver
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_dynamic_broadcast)
        timeChangeReceiver = TimeChangeReceiver()
        val intentFilter = IntentFilter()
        // 系统自带的时间改变的广播
        intentFilter.addAction("android.intent.action.TIME_TICK")
        registerReceiver(timeChangeReceiver, intentFilter)
    }

Hier wird registerReceiver() aufgerufen, um den Broadcast-Empfänger zu registrieren. Der erste Parameter gibt den Broadcast-Empfänger an, und der zweite Parameter ist ein IntentFilter, mit dem angegeben wird, welche Broadcasts akzeptiert werden sollen. android.intent.action.TIME_TICK ist die Sendung, die mit dem Android-System geliefert wird. Diese Sendung wird gesendet, wenn sich die Zeit ändert (in Minuten).

Denken Sie daran, dass die Sendung nach der Registrierung abgemeldet werden muss

    // 记得要注销掉接收器
    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(timeChangeReceiver)
    }

Führen Sie nun das Programm aus und es erscheint jede Minute eine Eingabeaufforderung.

 

2. Statische Registrierung und Senden einer Standardsendung

Wie bei der vorherigen dynamischen Registrierung kann der Rundfunkempfänger nicht registriert werden, wenn die Aktivität nicht gestartet wird. Aber die statische Registrierung hat keine solchen Einschränkungen.

Hier können wir einen Broadcast-Empfänger BroadcastReceiver erstellen.

 

  • Exportiert gibt an, ob es erlaubt ist, andere Sendungen als dieses Programm zu akzeptieren

  • Enabled gibt an, ob der Receiver gestartet ist.

Nachdem es erstellt wurde, müssen wir nur die Methode onReceiv() neu starten. In Androidmanifest.xml hat Android Studio diesen Receiver jedoch bereits für uns registriert.

        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
        </receiver>

Dann legen wir fest, welche Broadcast-Methode dieser Receiver empfängt, was auch in der Adroidmanifest.xml definiert ist.

        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter >
                <action android:name="com.bingbin.MY_BROADCAST" />
            </intent-filter>
        </receiver>

Hier definieren wir, dass wir den Broadcast com.bingbin.MY_BROADCAST empfangen, und jetzt implementieren wir das Senden eines Broadcasts.

Erstellen Sie eine neue Aktivität und fügen Sie eine Schaltfläche hinzu, um Broadcasts zu senden.

        btn_sendBroadcast.setOnClickListener {
            val intent = Intent("com.bingbin.MY_BROADCAST")
            intent.setPackage(packageName)
            sendBroadcast(intent)
        }

Die Methode zum Senden eines Broadcasts ist sendBoradcast(), die einen Intent() übergeben muss. Als wir es erstellt haben, haben wir angegeben, dass der Broadcast com.bingbin.MY_BROADCAST gesendet werden soll.

Hier ist eine Erklärung, warum es die Zeile intention.setPackage(packageName) gibt: Implizite Broadcasts beziehen sich auf jene Broadcasts, die kein sendendes Programm angeben, wie z. B. Power-On-Broadcasts und Time-Change-Broadcasts. Statisch registrierte Empfänger können diese Sendungen empfangen, aber dies führt dazu, dass einige Programme böswillig Sendungen empfangen, um Ressourcen zu verbrauchen, daher hat Android jetzt statisch registrierten Empfängern den Empfang impliziter Sendungen untersagt. Hier müssen wir also das Programm unter demselben Paketnamen angeben, um diese Sendung zu empfangen.

Nachdem Sie auf die Schaltfläche geklickt haben, wird eine Eingabeaufforderung angezeigt:

 

Um den Standard-Broadcast zu verifizieren, erstellen wir hier einen weiteren BroadcastReceiver, um auch den Broadcast com.bingbin.MY_BROADCAST zu empfangen

class AnotherReceiver : BroadcastReceiver() {
    override fun onReceive(context: Context, intent: Intent) {
        Toast.makeText(context, "another receiver also has received my broadcast",
            Toast.LENGTH_SHORT).show()
    }
}
        <receiver
            android:name=".AnotherReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter >
                <action android:name="com.bingbin.MY_BROADCAST" />
            </intent-filter>
        </receiver>

Drücken Sie zu diesem Zeitpunkt die Taste erneut, und es werden zwei Eingabeaufforderungen angezeigt.

 

 

3. Senden Sie eine ordnungsgemäße Sendung

Die Methode zum Senden einer Standardsendung ist sendBroadcast(), und die Methode zum Senden einer geordneten Sendung ist sendOrderBoradcast().

Lassen Sie uns eine weitere Schaltfläche hinzufügen, um eine bestellte Sendung zu senden.
 

       btn_sendOrderBroadcast.setOnClickListener {
            val intent = Intent("com.bingbin.MY_BROADCAST")
            intent.setPackage(packageName)
            sendOrderedBroadcast(intent, null)
        }

Der zweite Parameter kann auf null gesetzt werden.

Da es sich um eine geordnete Sendung handelt, wie sollte die Reihenfolge entschieden werden? Wir können die Gewichtung im Tag <intent-filter> bestimmen, das von Receiver in AndroidManifest.xml registriert wird.

        <receiver
            android:name=".AnotherReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="10">
                <action android:name="com.bingbin.MY_BROADCAST" />
            </intent-filter>
        </receiver>
        <receiver
            android:name=".MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="100">
                <action android:name="com.bingbin.MY_BROADCAST" />
            </intent-filter>
        </receiver>

Auf diese Weise empfängt MyBroadcastReceiver die Sendung zuerst und AnotherReceiver empfängt die Sendung später.

Wenn die Methode abortBroadcast() in der Logik aufgerufen wird, dass MyBroadcastReceiver die Sendung empfängt , kann die Sendung abgeschnitten werden, sodass AnotherReceiver die Sendung nicht empfangen kann.

Auf diese Weise erscheint nur die Meldung von MyBroadcastReceiver.

3. Stellen Sie Fragen

erste Frage

Ist der android.intent.action.TIME_TICK-Broadcast des bisher verwendeten Systems ein Standard-Broadcast oder ein bestellter Broadcast? Wie setze ich die Priorität für dynamisch registrierte BroadcastReceiver?

zweite Frage

Kann ein BroadcastReceiver mehrere Broadcasts empfangen? Wenn nicht, wenn eine Anforderung besteht, dass eine Logik nur dann ausgelöst wird, wenn zwei verschiedene spezifizierte Rundsendungen innerhalb eines Zeitraums empfangen werden, wie sollte sie implementiert werden?

dritte Frage

Wie ist der Lebenszyklus eines statisch registrierten Empfängers? Wenn mehrere Broadcasts hintereinander empfangen werden, handelt es sich um einen neuen Receiver oder jedes Mal um die gleiche Instanz?

4. Erkundungsfragen

erste Frage

Da es sich bei android.intent.action.TIME_TICK um eine implizite Übertragung handelt, können wir zunächst nicht die statische Registrierungsmethode zum Testen verwenden, sondern nur die dynamische Registrierung BroadcastReceiver.

Dann schreiben wir zwei interne BroadcastReceiver in eine Klasse, setzen Prioritäten für sie und der BroadcastReceiver mit höherer Priorität versucht, den Broadcast abzufangen, um zu sehen, ob der mit niedrigerer Priorität ihn noch empfängt.

Hier wird übrigens das Problem gelöst, wie man die Priorität des dynamisch eingetragenen BroadcastReceivers setzt. Wir müssen den Parameter IntentFilter() übergeben, wenn wir den Broadcast registrieren, und die Priorität kann im IntentFilter festgelegt werden.

class DynamicBroadcastActivity : AppCompatActivity() {
    lateinit var timeChangeReceiver: TimeChangeReceiver
    lateinit var anotherReceiver : AnotherTimeChangeReceiver
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_dynamic_broadcast)
        timeChangeReceiver = TimeChangeReceiver()
        val filter1 = IntentFilter()
        // 系统自带的时间改变的广播
        filter1.addAction("android.intent.action.TIME_TICK")
        filter1.priority = 100
        registerReceiver(timeChangeReceiver, filter1)
        anotherReceiver = AnotherTimeChangeReceiver()
        val filter2 = IntentFilter()
        // 系统自带的时间改变的广播
        filter2.addAction("android.intent.action.TIME_TICK")
        filter2.priority = 10
        registerReceiver(anotherReceiver, filter2)
    }
    // 记得要注销掉接收器
    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(timeChangeReceiver)
        unregisterReceiver(anotherReceiver)
    }
    inner class TimeChangeReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            Toast.makeText(context, "Time has changed!", Toast.LENGTH_SHORT).show()
            // 尝试拦截
            abortBroadcast()
        }
    }
    inner class AnotherTimeChangeReceiver : BroadcastReceiver() {
        override fun onReceive(context: Context?, intent: Intent?) {
            Toast.makeText(context, "AnotherTimeChangeReceiver has received the broadcast",
                Toast.LENGTH_SHORT).show()
        }
    }
}

Nach dem Testen wurde festgestellt, dass AnotherTimeChangeReceiver die Sendung immer noch empfing. Es zeigt, dass diese Systemsendung eine Standardsendung ist.

Wenn die Übertragung des Systems eine ordnungsgemäße Übertragung ist, dann registriert vermutlich ein bösartiges Programm einen BroadcastReceiver mit einer hohen Priorität, um ihn abzufangen, und es ist wahrscheinlich, dass Probleme auftreten.

zweite Frage

Um dies zu testen, definieren wir eine Schaltfläche, die zwei Broadcasts sendet.

    btn_sendTwoBroadcast.setOnClickListener { 
            val broad1 = Intent("com.bingbin.BROADCAST1")
            broad1.setPackage(packageName)
            val broad2 = Intent("com.bingbin.BROADCAST2")
            broad2.setPackage(packageName)
            sendBroadcast(broad1)
            sendBroadcast(broad2)
        }

Versuchen Sie dann, zwei Broadcasts im statisch registrierten Receiver zu empfangen.

        <receiver
            android:name=".StrongReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.bingbin.BROADCAST1"/>
                <action android:name="com.bingbin.BROADCAST2"/>
            </intent-filter>
        </receiver>

Fügen Sie dann die Verarbeitungslogik hinzu

class StrongReceiver : BroadcastReceiver() {
    var i = 0
    override fun onReceive(context: Context, intent: Intent) {
        Toast.makeText(context, "I have received a broadcast $i", Toast.LENGTH_SHORT).show()
        i += 1
    }
}

Um zu unterscheiden, wie oft es aufgerufen wurde, habe ich eine globale Variable hinzugefügt.

Habe das Protokoll überprüft

 

Es wurde festgestellt, dass die Ausgabe zweimal ausgegeben wurde, aber ich habe nichts geändert. Das ist ein bisschen seltsam.

Später habe ich i in eine statische Klasse gesteckt

 

Die Ausgabe wird als korrekt befunden.

Hier kann also festgelegt werden, dass ein BroadcastReceiver angeben kann, mehrere Broadcasts zu empfangen.

dritte Frage

Tatsächlich können wir aus der Praxis der zweiten Frage erraten, dass jedes Mal, wenn ein Empfänger eine Sendung empfängt, es eine neue Instanz sein sollte.

Lassen Sie uns noch einmal überprüfen

class MyBroadcastReceiver : BroadcastReceiver() {
    init {
        Log.d("MyBroadcastReceiver", "创建了一个新的实例")
    }
    override fun onReceive(context: Context, intent: Intent) {
        Toast.makeText(context, "I have received my own broadcast!",
            Toast.LENGTH_SHORT).show()
    }
}

Hier habe ich dem Konstruktor von MyBroadcastReceiver einen Satz der Protokollausgabe hinzugefügt.

 

Sie werden feststellen, dass der statisch registrierte Empfänger jedes Mal, wenn ein Broadcast empfangen wird, eine neue Instanz erstellt.

Dann kommt die Frage, wird die zuvor erstellte Instanz immer im Speicher existieren? Wann wird es zerstört? Wird es OOM verursachen, wenn es nicht zerstört wird?

Dann fand ich einen solchen Kommentar im Quellcode von onReceive()

Wenn dieser BroadcastReceiver über ein <receiver>-Tag gestartet wurde, ist das Objekt nach der Rückkehr von dieser Funktion nicht mehr aktiv. Das bedeutet, dass Sie keine Operationen ausführen sollten, die asynchron ein Ergebnis an Sie zurückgeben.

Wir können also sehen, dass ein statisch registrierter Empfänger nach dem Aufruf von onReceive() zerstört wird. Es besteht kein Speicherrisiko.

Wenn wir uns dynamisch registrieren, müssen wir auch darauf achten, dass unregisterReceiver() aktiv aufgerufen wird, um den Receiver abzubrechen, da sonst die Gefahr von Speicherlecks besteht.

Supongo que te gusta

Origin blog.csdn.net/qq_43478882/article/details/122262862
Recomendado
Clasificación