Chapter VI Broadcasting
-
Radio classification
-
Standard radio
A broadcast executed asynchronously that is received by all broadcastreceivers at approximately the same time after the broadcast is sent.
-
Orderly broadcast
Synchronous broadcast. After a broadcast is sent, only one BroadcastReceiver can receive the broadcast at the same time. When the logic in the BroadcastReceiver completes, the broadcast continues.
-
-
Receive the broadcast
-
Registration way
-
Dynamic registration, registered in code
-
Static registration,
AndroidManifest.xml
Registered in
-
-
Dynamic registration
class TimeChangeReceiverActivity : AppCompatActivity() { private lateinit var timeChangedReceiver: TimeChangedReceiver override fun onCreate(savedInstanceState: Bundle?). { super.onCreate(savedInstanceState) setContentView(R.layout.activity_time_change_receiver) timeChangedReceiver = TimeChangedReceiver() val intentFilter = IntentFilter() intentFilter.addAction("android.intent.action.TIME_TICK") registerReceiver(timeChangedReceiver, intentFilter) } override fun onDestroy(a) { super.onDestroy() unregisterReceiver(timeChangedReceiver) } class TimeChangedReceiver : BroadcastReceiver() { override fun onReceive(context: Context? , intent:Intent?). { Toast.makeText(context, "Time has changed", Toast.LENGTH_SHORT).show() } } } Copy the code
⚠️ Dynamic registration of BroadcastReceiver must be unregistered. Otherwise, memory leaks will occur.
-
Static registration
All implicit broadcasts after Android8.0 do not allow static registration. Implicit broadcasts are those that do not specify to which application they are sent.
-
New->Other->BroadcastReceiver Creates the BroadcastReceiver file.
class BootCompletedReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { // This method is called when the BroadcastReceiver is receiving an Intent broadcast. TODO("BootCompletedReceiver.onReceive() is not implemented")}}Copy the code
-
Androidmanifest.xml file registration
<manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.youngly.firstlineofcode"> <! -- Permission statement --> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> <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/Theme.FirstLineOfCode"> <! -- Enabled Whether to enable exported whether to receive broadcasts outside this program --> <receiver android:name=".chapter6.BootCompletedReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="android.intent.action.BOOT_COMPLETED"/> </intent-filter> </receiver>.</application> </manifest> Copy the code
⚠️ do not perform time-consuming operations in the onReceive() method. BroadcastReceiver does not allow threads to start.
-
-
-
Sends custom standard broadcasts
<receiver android:name=".chapter6.standardbroadcast.MyStandardReceiver" android:enabled="true" android:exported="true"> <intent-filter> <action android:name="com.youngly.firstlineofcode.MyStandardReceiver" /> </intent-filter> </receiver> Copy the code
class MyStandardReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { Toast.makeText(context, "received in MyStandardReceiver", Toast.LENGTH_SHORT).show() } } Copy the code
fun myStandardBroadcastReceiver(view: View) { val intent = Intent("com.youngly.firstlineofcode.MyStandardReceiver") intent.`package` = packageName sendBroadcast(intent) } Copy the code
⚠️ After Android 8.0, BroadcastReceiver statically registered can’t receive implicit broadcasts, which by default are custom broadcasts. So the setPackage() method is called to specify which application this broadcast is sent to, making it an explicit broadcast.
-
Send ordered broadcast
<receiver android:name=".chapter6.OrderBroadcast.OrderReceiver" android:enabled="true" android:exported="true"> <intent-filter android:priority="1000"> <action android:name="com.youngly.firstlineofcode.MyStandardReceiver" /> </intent-filter> </receiver> Copy the code
val intent = Intent("com.youngly.firstlineofcode.MyStandardReceiver") intent.`package` = packageName sendOrderedBroadcast(intent, null) Copy the code
class OrderReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { // This method is called when the BroadcastReceiver is receiving an Intent broadcast. Toast.makeText(context, "received in OrderReceiver", Toast.LENGTH_SHORT).show() abortBroadcast() } } Copy the code
android:priority
Setting the PrioritysendOrderedBroadcast(intent, null)
Send ordered broadcastabortBroadcast()
Truncation radio
-
Kotlin classroom
-
Higher-order functions
A function is called a higher-order function if it takes another function as an argument, or if the type of the return value is another function.
Function type definition:
(String, Int) - >Unit Copy the code
The key to function types is to declare the parameters and return values that the function receives. -> The left side is the function parameter. Multiple parameters are separated by,. If no arguments are received, write a pair of empty parentheses. -> The right part is used to declare the return value type of the function.
fun example(func: (String.Int) - >Unit){}Copy the code
In the example above, the example() function is the higher-order function that takes a function as an argument
fun main(a) { println(operatorInts(1.2, ::plus)) } fun operatorInts(a: Int, b: Int.operator: (Int.Int) - >Int): Int { return operator(a, b) } fun plus(a: Int, b: Int): Int { return a + b } Copy the code
::plus A method of passing a function as an argument to a function.
-
Inline function
-
Higher-order function principle analysis:
fun main(a) { operatorInts(4.2) { a, b -> a / b } } fun operatorInts(a: Int, b: Int.operator: (Int.Int) - >Int): Int { return operator(a, b) } Copy the code
This code calls the operatorInts() function and specifies the quotient operation on the two integer arguments passed in via a Lambda expression. Kotlin code eventually compiles to Java bytecode, but there is no concept of higher-order functions in Java.
The idea is that the Java compiler translates the syntax of a higher-order function into a Java supported syntax structure.
public class HighOrderFuncTest { public static void main(String[] args) { int result = operatorIntegers(4.2.new Function2<Integer, Integer, Integer>() { @Override public Integer invoke(Integer integer, Integer integer2) { returninteger / integer2; }}); }public static int operatorIntegers(int a, int b, Function2<Integer, Integer, Integer> operator) { returnoperator.invoke(a, b); }}Copy the code
Here Lambda expressions become the Function2 interface, which is Kotlin’s built-in interface with an invoke() function to be implemented.
Here you’ll find that the Lambda expressions we’ve been using have been converted to an anonymous inner class implementation underneath. This means that every time we call a Lambda expression, a new anonymous inner class instance is created. There are, of course, additional memory and performance costs.
Kotlin provides inline functions that completely eliminate runtime overhead associated with Lambda expressions.
-
Use of inline functions
inline fun operatorInts(a: Int, b: Int.operator: (Int.Int) - >Int): Int { return operator(a, b) } Copy the code
The usage is simple, just use the inline keyword declaration when defining higher-order functions
-
How inline functions work
fun main(a) { val a = 4 val b = 2 a / b } Copy the code
This is equivalent to tiling operatorInts()
-
-
noinline
If a higher-order function receives two or more arguments of function type inline, the Kotlin compiler automatically inlines all referenced Lambda expressions.
The noinline keyword can be used when we want to inline only one of the Lambda expressions
inline fun inlineTest(block1: () -> Unit.noinline block2: () -> Unit){}Copy the code
Because the inline function type argument is replaced by code at compile time, it has no real attribute argument
inline fun inlineTest(block1: () -> Unit, block2: () -> Unit): () - >Unit { // Block2 will be replaced by code instead of function type return block2 } Copy the code
// Add the noinline keyword and compile 👌 inline fun inlineTest(block1: () -> Unit.noinline block2: () -> Unit): () - >Unit { return block2 } Copy the code
-
crossinline
Take a look at the code below:
fun main(a) { println("main start") inLineTest { println("lambda run") return } println("main end")}inline fun inLineTest(block: () -> Unit) { println("out method start") block() println("out method end")}Copy the code
Actual output:
main start out method start lambda run Copy the code
Return is the main() function of a direct return, since inline is the equivalent of tiling a function
fun main(a) { println("main start") noinlineTest({ -> print("") }, { -> print("noinline lambda run") // return compiler error return }) println("main end")}inline fun noinlineTest(block: () -> Unit.noinline block2: () -> Unit) { println("out method start") block2() println("out method end")}Copy the code
Why does the above return compile an error?
In the above example, an inline return returns the outermost call. This causes a problem. A return from an inline function terminates the call to the outermost function. So Kotlin specifies that only Lambda expressions referenced by inline functions can use the return keyword for function returns
Is there a way to use return in this example? Local returns can be made using the return@ function name, modified as follows
fun main(a) { println("main start") noinlineTest({ -> print("") }, { -> print("noinline lambda run") return@noinlineTest }) println("main end")}inline fun noinlineTest(block: () -> Unit.noinline block2: () -> Unit) { println("out method start") block2() println("out method end")}Copy the code
Actual output:
main start out method start noinline lambda runout method end main end Copy the code
See the example below:
inline fun inlineWithRunable(block: () -> Unit) { Runnable() { // Compile error block() } } Copy the code
Lambda expressions referenced by inline functions allow return using the return keyword, but since we are using it in anonymous classes, it is not possible to return the outermost call function. We can only return functions in anonymous classes by adding the Crossinline keyword. Ensure that the outermost function return keyword is not used in the Lambda referenced by an inline function, but local returns can be made using the return@ inline function name.
inline fun inlineWithRunable(crossinline block: () -> Unit) { Runnable() { block() } } Copy the code
-