分类 Android 下的文章

package com.example.msdksample.utils

import android.util.Log

class Logger(private val tag: String) {
    fun info(message: String) {
        Log.i(tag, message)
    }

    fun error(message: String, throwable: Throwable? = null) {
        if (throwable != null) {
            Log.e(tag, message, throwable)
        } else {
            Log.e(tag, message)
        }
    }

    fun debug(message: String) {
        Log.d(tag, message)
    }

    fun warn(message: String) {
        Log.w(tag, message)
    }
}

package com.example.msdksample.activity

import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
import android.content.pm.PackageManager
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import android.widget.TextView
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.msdksample.MyApplication
import com.example.msdksample.R
import com.google.android.material.snackbar.Snackbar

class MainActivity : AppCompatActivity() {

    private lateinit var tvAppActivation: TextView
    private lateinit var btnFlightController: Button

    // Use enum for better type safety
    private enum class ActivationState {
        ACTIVATED,
        NOT_ACTIVATED
    }

    private var appActivationState: ActivationState = ActivationState.NOT_ACTIVATED

    // BroadcastReceiver to monitor application registration and product connection
    private val registerReceiver = object : BroadcastReceiver() {
        override fun onReceive(context: Context, intent: Intent) {
            when (intent.action) {
                MyApplication.REGISTER_SUCCESS -> {
                    appActivationState = ActivationState.ACTIVATED
                    updateActivationUI()
                    showMessage(getString(R.string.register_success))
                }
                MyApplication.REGISTER_FAILURE -> {
                    val errorMessage = intent.getStringExtra("error_message") ?: getString(R.string.unknown_error)
                    appActivationState = ActivationState.NOT_ACTIVATED
                    updateActivationUI()
                    showMessage(getString(R.string.register_failure, errorMessage))
                }
                MyApplication.PRODUCT_CONNECT -> {
                    showMessage(getString(R.string.product_connect))
                }
                MyApplication.PRODUCT_DISCONNECT -> {
                    showMessage(getString(R.string.product_disconnect))
                }
                MyApplication.PRODUCT_CHANGED -> {
                    showMessage(getString(R.string.product_changed))
                }
            }
        }
    }

    private var isReceiverRegistered = false

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        initViews()
        checkAndRequestPermissions()
    }

    private fun initViews() {
        tvAppActivation = findViewById(R.id.tv_status_application)
        btnFlightController = findViewById(R.id.btn_flight_controller)

        btnFlightController.setOnClickListener {
            if (appActivationState == ActivationState.ACTIVATED) {
                val intent = Intent(this, FlightActivity::class.java)
                startActivity(intent)
            } else {
                showMessage(getString(R.string.app_not_activated))
            }
        }

        updateActivationUI()
    }

    private fun updateActivationUI() {
        val statusText = when (appActivationState) {
            ActivationState.ACTIVATED -> getString(R.string.activation_status_activated)
            ActivationState.NOT_ACTIVATED -> getString(R.string.activation_status_not_activated)
        }
        tvAppActivation.text = getString(R.string.activation_status_label, statusText)
    }

    override fun onStart() {
        super.onStart()
        registerBroadcastReceiver()
    }

    override fun onStop() {
        unregisterBroadcastReceiver()
        super.onStop()
    }

    private fun registerBroadcastReceiver() {
        if (!isReceiverRegistered) {
            val filter = IntentFilter().apply {
                addAction(MyApplication.REGISTER_SUCCESS)
                addAction(MyApplication.REGISTER_FAILURE)
                addAction(MyApplication.PRODUCT_CONNECT)
                addAction(MyApplication.PRODUCT_DISCONNECT)
                addAction(MyApplication.PRODUCT_CHANGED)
            }

            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
                registerReceiver(registerReceiver, filter, Context.RECEIVER_NOT_EXPORTED)
            } else {
                registerReceiver(registerReceiver, filter)
            }

            isReceiverRegistered = true
        }
    }

    private fun unregisterBroadcastReceiver() {
        if (isReceiverRegistered) {
            try {
                unregisterReceiver(registerReceiver)
                isReceiverRegistered = false
            } catch (e: IllegalArgumentException) {
                // Receiver was already unregistered
            }
        }
    }

    /* Permission Handling */

    private fun getRequiredPermissions(): Array<String> {
        val basePermissions = mutableListOf(
            android.Manifest.permission.RECORD_AUDIO,
            android.Manifest.permission.INTERNET,
            android.Manifest.permission.CHANGE_WIFI_STATE,
            android.Manifest.permission.ACCESS_WIFI_STATE,
            android.Manifest.permission.ACCESS_NETWORK_STATE,
            android.Manifest.permission.CAMERA,
            android.Manifest.permission.ACCESS_COARSE_LOCATION,
            android.Manifest.permission.ACCESS_FINE_LOCATION
        )

        // Only add storage permissions for older Android versions
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
            basePermissions.add(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
            basePermissions.add(android.Manifest.permission.READ_EXTERNAL_STORAGE)
        }

        return basePermissions.toTypedArray()
    }

    private fun checkAndRequestPermissions() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
            if (!hasAllPermissions()) {
                requestAllPermissions()
            } else {
                proceedWithAppFunctionality()
            }
        } else {
            proceedWithAppFunctionality()
        }
    }

    private fun hasAllPermissions(): Boolean {
        return getRequiredPermissions().all {
            ContextCompat.checkSelfPermission(this, it) == PackageManager.PERMISSION_GRANTED
        }
    }

    private fun requestAllPermissions() {
        ActivityCompat.requestPermissions(this, getRequiredPermissions(), PERMISSIONS_REQUEST_CODE)
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)

        if (requestCode == PERMISSIONS_REQUEST_CODE) {
            if (grantResults.isNotEmpty() && grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
                proceedWithAppFunctionality()
            } else {
                showMessage(getString(R.string.permissions_required))
            }
        }
    }

    private fun proceedWithAppFunctionality() {
        showMessage(getString(R.string.permissions_granted))
    }

    private fun showMessage(message: String) {
        // Use Snackbar instead of Toast for better UX
        Snackbar.make(
            findViewById(android.R.id.content),
            message,
            Snackbar.LENGTH_SHORT
        ).show()
    }

    companion object {
        private const val PERMISSIONS_REQUEST_CODE = 102
    }
}

编程之本:变量和函数

变量

Kotlin 中定义一个变量,只允许在变量前声明两种关键字:valvar

由于大疆新的无人机采用Mobile SDK 5.x版本(Kotlin),而之前学习的版本是4.x(Java),并且大疆对于5.x版本的文档写的实在不怎么样(相比4.x来说),所以从新记录一下。

The lateinit keyword in Kotlin is used to declare(声明) a property that will be initialized later. It allows you to avoid(避免) null checks or the use of the null type for properties that you are certain will be initialized before use, but for some reason, you can't initialize them immediately(立即) at declaration.