移動開發筆記(八)系統廣播 和Kotlin高階函數

廣播機制

1.標準廣播 normal broadcasts 一種完全異步執行的廣播,在廣播發出之後,所有的廣播接收器幾乎都會在同一時間接收到這條廣播,因此他們之間沒有任何的先後順序。

特點:效率高;缺點:無法攔截。
2.有序廣播 ordered broadcaasts 一種同步執行的廣播,在廣播發出之後,同一時刻只會有一個廣播接收器能夠接收到這條廣播,當該廣播接收器執行完OnReceive()方法邏輯後,廣播纔會繼續傳遞。

特點:優先級高者會先接收到廣播,並且可以攔截該條廣播是否繼續傳遞

1.動態註冊監聽時間變化

class MainActivity : AppCompatActivity() {
    lateinit var timeChangeReceiver : TimeChangeReceiver;

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        val intentFiler=IntentFilter()
        intentFiler.addAction("android.intent.action.TIME_TICK")
        timeChangeReceiver =TimeChangeReceiver()
        registerReceiver(timeChangeReceiver,intentFiler)
    }

    override fun onDestroy() {
        super.onDestroy()
        unregisterReceiver(timeChangeReceiver)
    }
    inner class TimeChangeReceiver : BroadcastReceiver(){
        override fun onReceive(context: Context?, intent: Intent?) {
            Toast.makeText(context,"時間線發生改變",Toast.LENGTH_SHORT).show()
        }

    }
}

完整的系統廣播列表:/platforms/<任意 android api 版本>/data/broadcast_actions.txt

2.靜態註冊實現開機啓動

特殊的系統廣播列表:網址
右擊com.example.broadcasttest包->New->Other->Broadcast Receiver。創建類命爲BootCompleterReceiver(會自動在AndroidManifest.xml文件)
Exported屬性表示是否允許這個BroadcastReceiver接收。
Enabled屬性表示是否啓用這個BroadcastReceiver。

class BootCompleteReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        // This method is called when the BroadcastReceiver is receiving an Intent broadcast.
        Toast.makeText(context,"Boot Complete",Toast.LENGTH_LONG).show()
    }
}

AndroidManifest.xml文件:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.broadcast">
      <!--增加-->
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"></uses-permission>
    <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/AppTheme">
        <receiver
            android:name=".BootCompleteReceiver"
            android:enabled="true"
            android:exported="true">
            <!--增加-->
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED"></action>
            </intent-filter>
        </receiver>

        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

注意:在onReceive()方法中不要添加過多的邏輯或者耗時操作。應爲BroadcastReciver中不允許開啓線程,當哦那Receive()方法允許較長時間沒有結束,程序會出錯

3.發送自定義廣播

3.1發送標準廣播
首先創建一個接收廣播的MyBroadcastReceiver

class MyBroadReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        // This method is called when the BroadcastReceiver is receiving an Intent broadcast.
        Toast.makeText(context,"收到MyBroadcast",Toast.LENGTH_SHORT).show()
    }
}

再在AndroidManifest.xml文件中添加配置

...
<receiver
            android:name=".MyBroadReceiver"
            android:enabled="true"
            android:exported="true">
            <intent-filter>
                <action android:name="com.example.broadcast.MY_BROADCAST"></action>
            </intent-filter>
        </receiver>
...

修改activity_main.xml,添加發送廣播按鈕

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity"
    android:orientation="vertical">

    <Button
        android:id="@+id/button"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:text="發送廣播"></Button>

</LinearLayout>

在MainActivity中註冊按鈕點擊事件

...
 button.setOnClickListener {
            val intent = Intent("com.example.broadcast.MY_BROADCAST")
            intent.setPackage(packageName)
            sendBroadcast(intent)
        }
...

在android8.0系統之後靜態註冊的BroadcastReceiver是無法接收隱式廣播,英雌這裏一定要調用setPackage()方法,指定這條廣播是發送給哪個應用程序的,讓它編程一條顯式程序
3.2發送有序廣播
新創建一個AnotherBroadcastReceiver

class AnotherBroadcastReceiver : BroadcastReceiver() {

    override fun onReceive(context: Context, intent: Intent) {
        // This method is called when the BroadcastReceiver is receiving an Intent broadcast.
       Toast.makeText(context,"AnotherBroadcast接收到了",Toast.LENGTH_SHORT).show()
       //調用   abortBroadcast()方法,這條廣播將截斷
        abortBroadcast()
    }
}

再在AndroidManifest.xml文件中添加配置
設置BroadcastReceiver先後順序

<receiver
            android:name=".AnotherBroadcastReceiver"
            android:enabled="true"
            android:exported="true">
            <!--優先級設置爲100-->
            <intent-filter android:priority="100">
                <action android:name="com.example.broadcast.MY_BROADCAST"></action>
            </intent-filter>
        </receiver>

在MainActivity中註冊按鈕點擊事件

 button.setOnClickListener {
            val intent = Intent("com.example.broadcast.MY_BROADCAST")
            intent.setPackage(packageName)
           // sendBroadcast(intent)
            sendOrderedBroadcast(intent,null)
        }

3.3創建一個強制下線的功能
創建一個ActivitiesCollector

object ActivityCollector {
    private val activities=ArrayList<Activity>()
    fun addActivity(activity: Activity){
        activities.add(activity)

    }

    fun removeActivity(activity: Activity){
        activities.remove(activity)
    }

    fun finshAll(){
        for (activity in activities){
            if(!activity.isFinishing){
                activity.finish()
            }
        }
        activities.clear()
    }
}

創建BaseActivity

open class BaseActivity :AppCompatActivity(){
    lateinit var reciver : ForceOfflineReceiver
    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)
        ActivityCollector.addActivity(this)
    }

    override fun onResume() {
        super.onResume()
        val intentFilter = IntentFilter()
        intentFilter.addAction("com.example.broadcastbestpractice.FORCE_OFFLINE")
        reciver=ForceOfflineReceiver()
        registerReceiver(reciver,intentFilter)
    }

    override fun onPause() {
        super.onPause()
        unregisterReceiver(reciver)
    }
    override fun onDestroy() {
        super.onDestroy()
        ActivityCollector.removeActivity(this)
    }
    inner class ForceOfflineReceiver : BroadcastReceiver(){
        override fun onReceive(context: Context, intent: Intent) {
            AlertDialog.Builder(context).apply {
                setTitle("Warning")
                setMessage("你已經被強制下線")
                //setCancelable(false)表示對話框不可取消
                setCancelable(false)
                setPositiveButton("OK"){
                    _,_ ->ActivityCollector.finshAll()//銷燬所有的Activity
                    val i = Intent(context,LoginActivity::class.java)
                    context.startActivity(i)
                }
                show()
            }
        }
    }
}

創建LoginActivity

class LoginActivity : BaseActivity(){
    override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
        super.onCreate(savedInstanceState, persistentState)
        setContentView(R.layout.activity_login)
        login.setOnClickListener {
            val account=accountEdit.text.toString()
            val password =passwordEdit.text.toString()
            //判斷賬號如果是123456就登陸成功
            if (account=="123456"&&password=="123456"){
                val intent= Intent(this,MainActivity::class.java)
                startActivity(intent)
                finish()
            }else{
                Toast.makeText(this,"賬號或者密碼出錯", Toast.LENGTH_SHORT).show()
            }
        }
    }
}

修改MainActivity

class MainActivity : BaseActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        forceOffline.setOnClickListener {
            val intent=Intent("com.example.broadcastbestpractice.FORCE_OFFLINE")
            sendBroadcast(intent)
        }
    }
}

高階函數

1定義高階函數
基本規則:(String,Int)-> Unit

舉例:

fun num1AndNum2(num1 : Int,num2 : Int,operation: (Int,Int) -> Int) : Int{
val result = operation(num1,num2)
return result
}

fun plus(num1 : Int,num2 : Int) : Int{
 return num1+num2
}

fun minus(num1 : Int,num2 : Int):Int{
return num1-num2
}

fun main(){
	val num1=100
	valnum2=80
	val result1=numAndNum2(num1,num2,::plus)
	val result2=numAndNum2(num1,num2,::minus)
}

2.內聯函數
關鍵字:inline
因爲Kotlin高階函數背後每調用一次Lambda表達式,都會創建一個新的匿名類實例,當然這也會增加額外的內存和性能開銷.爲解決這個問題,Kotlin提供了內聯函數。

inline  fun num1AndNum2(num1 : Int,num2 : Int,operation: (Int,Int) -> Int) : Int{
val result = operation(num1,num2)
return result
}

3.noinline與crossinline
如果只想內聯其中的一個Lambda表達式,可以使用noinline關鍵字

inline fun inlineTest(block1: () -> Unit,noinline block2: () -> Unit){

}

內聯函數所引用的Lambda表達式中可以使用return,而非內聯函數只能進行局部返回。

如果我們在高階函數中創建了另外的Lambda或者匿名類的實現,並且在這些實現中調用函數類型參數,此時再將高階函數聲明成內聯函數,就一定會提示錯誤(不能進行外層調用函數返回,最多隻能對匿名名類中的函數調用進行返回,因此提示了上述錯誤)

inline fun runRunnable(block : () -> Unit){
	val runnable = Runnable{
	block()//報錯地點
}
runnable.run()
}

這種情況可以通過關鍵字crossinline解決(crossinline就像契約一樣,用於保證在內聯函數的Lambda表達式中一定不會使用return關鍵字)

3.git
下載地址:https://gitforwindows.org/

1首先配置一下你的身份

git config --global user.name "Peter"
git config --global user.email "[email protected]"

2先切換到項目目錄下
如何切換到帶有空格的目錄

比如目錄爲 Application Support
操作方法爲: export path="Application Support"
                         cd "$path"

輸入如下命令

git init

可以通過 la -al命令查看一下,如果想刪除本地倉庫,刪除隱藏的.git目錄就行了

3.提交本地代碼

git add build.gradle//添加build.gradle文件
git add app//表示添加app目錄下所有的文件
git add .//表示添加所有的文件
git commit -m "First commit"//表示提交事務,一定要-m參數加上描述信息
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章