Chapter VI Broadcasting

  1. Radio classification

    1. Standard radio

      A broadcast executed asynchronously that is received by all broadcastreceivers at approximately the same time after the broadcast is sent.

    2. 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.

  2. Receive the broadcast

    1. Registration way

      1. Dynamic registration, registered in code

      2. Static registration,AndroidManifest.xmlRegistered in

    2. 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.

    3. 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.

  3. 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.

  4. 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:prioritySetting the Priority
    • sendOrderedBroadcast(intent, null)Send ordered broadcast
    • abortBroadcast()Truncation radio
  5. Kotlin classroom

    1. 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.

    2. Inline function

      1. 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.

      2. 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

      3. How inline functions work

        fun main(a) {
            val a = 4
            val b = 2
            a / b
        }
        Copy the code

        This is equivalent to tiling operatorInts()

    3. 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
    4. 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