国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Android 沾包處理,以串口接入為例 (usb-serial-for-android)

這篇具有很好參考價(jià)值的文章主要介紹了Android 沾包處理,以串口接入為例 (usb-serial-for-android)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問。

1. 前言

我們?cè)谕ㄟ^串口、TCPUDP等方式接收協(xié)議的時(shí)候,由于單次接收數(shù)據(jù)有限,導(dǎo)致一條命令可能被分割成多次進(jìn)行接收。
這種情況下,就需要進(jìn)行沾包處理,使多次接收的數(shù)據(jù),合并成一條數(shù)據(jù)。本文通過博主本人一個(gè)真實(shí)的工作案例,實(shí)例講解Android串口的接入和對(duì)于沾包的處理。

2. 協(xié)議

我們以下方這個(gè)協(xié)議為例
這是個(gè)串口協(xié)議,Android設(shè)備通過監(jiān)聽串口,讀取到具體的數(shù)據(jù)

前導(dǎo)幀 長(zhǎng)度 內(nèi)容 校驗(yàn)
長(zhǎng)度 1Bit 1Bit 0~255Bit 1Bit
0xAA 0~255 Json 校驗(yàn)結(jié)果

可以看到,前導(dǎo)幀為1個(gè)字節(jié),每當(dāng)讀取到0xAA,就代表一條命令的開始。
第二個(gè)字節(jié)是長(zhǎng)度,占1個(gè)字節(jié),表示內(nèi)容部分占用多少個(gè)字節(jié)。
最后一個(gè)字節(jié)用特定的算法,將命令的前面部分進(jìn)行計(jì)算后得到的值,用來校驗(yàn)這條命令是否正確。

  • 如果命令正確,那就正常處理
  • 如果命令錯(cuò)誤,就作丟棄處理

3. 驗(yàn)證串口硬件是否正常

可以在平板或手機(jī)上下載usb調(diào)試寶,設(shè)置好波特率 (比如115200,這個(gè)根據(jù)串口設(shè)備設(shè)置),然后即可監(jiān)聽到串口發(fā)送的數(shù)據(jù)了。

Android 沾包處理,以串口接入為例 (usb-serial-for-android)

4. 串口接入

我們這里使用了usb-serial-for-android這個(gè)串口庫

4.1 添加Jitpack倉庫

repositories {
    ...
    maven { url 'https://jitpack.io' }
}

4.2 添加usb-serial-for-android依賴

implementation 'com.github.mik3y:usb-serial-for-android:3.4.6'

4.3 獲取UsbManager

val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager

4.4 判斷是否有權(quán)限

fun hasPermission(): Boolean {
    val driver = getDriver() ?: return false
    return usbManager.hasPermission(driver.device)
}

private fun getDrivers(): MutableList<UsbSerialDriver> {
    return UsbSerialProber.getDefaultProber().findAllDrivers(usbManager)
}

private fun getDriver(): UsbSerialDriver? {
    val availableDrivers = getDrivers()
    if (availableDrivers.isEmpty()) {
        log("availableDrivers is empty.")
        return null
    }

    return availableDrivers[0]
}

4.5 請(qǐng)求權(quán)限

如果沒有權(quán)限,需要先申請(qǐng)權(quán)限,這一步很主要,要不然后面肯定是讀取不到串口的數(shù)據(jù)的。

fun requestPermission() {
    val driver = getDriver() ?: return
    val flags =
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
    val permissionIntent = PendingIntent.getBroadcast(
        context,
        0,
        Intent("com.android.example.USB_PERMISSION"),
        flags
    )
    usbManager.requestPermission(driver.device, permissionIntent)
}

4.6 打開設(shè)備

val driver = getDriver() ?: return
val connection = usbManager.openDevice(driver.device) ?: return
log("connection:$connection")

port = driver.ports[0] // Most devices have just one port (port 0)
port?.open(connection)
port?.setParameters(params.baudRate, params.dataBits, params.stopBits, params.parity)

usbIoManager = SerialInputOutputManager(port, this)
usbIoManager.start()

注意這里SerialInputOutputManager有個(gè)監(jiān)聽,onNewData就是處理接收數(shù)據(jù)的地方了。

override fun onNewData(data: ByteArray?) {
    //當(dāng)接收到數(shù)據(jù)
}

override fun onRunError(e: Exception?) {
    //當(dāng)運(yùn)行出錯(cuò)
}

4.7 關(guān)閉設(shè)備

當(dāng)我們要退出App的時(shí)候,需要去關(guān)閉串口

fun closeDevice() {
    port?.close()
    port = null
}

5. 沾包處理

當(dāng)我們?cè)?code>onNewData里,我們需要進(jìn)行沾包處理。
這里我處理沾包的一個(gè)思路是在onNewData接收到的數(shù)據(jù),存儲(chǔ)到一個(gè)地方,然后另起一個(gè)線程,在那個(gè)線程中,再去讀取數(shù)據(jù)。這樣,就可以很好地規(guī)避在onNewData里,一股腦給到一個(gè)ByteArray數(shù)組,導(dǎo)致的拆解數(shù)據(jù),處理多種異常情況的問題了。

onNewData接收到的數(shù)據(jù),我們可以存儲(chǔ)到Queue(隊(duì)列),隊(duì)列的特性是先進(jìn)先出(通常但并非一定),這樣就可以確保我們先接收到的數(shù)據(jù)先被讀取處理,并且也簡(jiǎn)化了處理的流程。

5.1 常見的Queue

常見的Queue有這幾種,我們這里選用的是LinkedBlockingQueue,沒有數(shù)據(jù)的時(shí)候,它具有自動(dòng)阻塞的能力。

  • ArrayBlockingQueue : 數(shù)組實(shí)現(xiàn)的有界隊(duì)列,會(huì)自動(dòng)阻塞,根據(jù)調(diào)用api不同,有不同特性,當(dāng)隊(duì)列容量不足時(shí),有阻塞能力
    • boolean add(E e):在容量不足時(shí),拋出異常。
    • void put(E e):在容量不足時(shí),阻塞等待。
    • boolean offer(E e):不阻塞,容量不足時(shí)返回false,當(dāng)前新增數(shù)據(jù)操作放棄。
    • boolean offer(E e, long timeout, TimeUnit unit):容量不足時(shí),阻塞times時(shí)長(zhǎng)(單位為timeunit),如果在阻塞時(shí)長(zhǎng)內(nèi),有容量空閑,新增數(shù)據(jù)返回true。如果阻塞時(shí)長(zhǎng)范圍內(nèi),無容量空閑,放棄新增數(shù)據(jù),返回false。
  • LinkedBlockingQueue:鏈?zhǔn)疥?duì)列,隊(duì)列容量不足或?yàn)?code>0時(shí)自動(dòng)阻塞
    • void put(E e):自動(dòng)阻塞,隊(duì)列容量滿后,自動(dòng)阻塞。
    • E take():自動(dòng)阻塞,隊(duì)列容量為0后,自動(dòng)阻塞。
  • ConcurrentLinkedQueue : 基礎(chǔ)鏈表同步隊(duì)列
    • boolean offer(E e):入隊(duì)。
    • E peek():查看queue中的首數(shù)據(jù)。
    • E poll():取出queue中的首數(shù)據(jù)。
  • DelayQueue: 延時(shí)隊(duì)列,根據(jù)比較機(jī)制,實(shí)現(xiàn)自定義處理順序的隊(duì)列。常用于定時(shí)任務(wù),如:定時(shí)關(guān)機(jī)。
    • int compareTo(Delayed o):比較大小,自動(dòng)升序。
    • 比較方法建議和getDelay方法配合完成。如果在DelayQueue是需要按時(shí)完成的計(jì)劃任務(wù),必須配合getDelay方法完成。
    • long getDelay(TimeUnit unit):獲取計(jì)劃時(shí)長(zhǎng)的方法,根據(jù)參數(shù)TimeUnit來決定,如何返回結(jié)果值。
  • LinkedTransferQueue : 轉(zhuǎn)移隊(duì)列
    • boolean add(E e):隊(duì)列會(huì)保存數(shù)據(jù),不做阻塞等待。
    • void transfer(E e):是TransferQueue的特有方法。必須有消費(fèi)者(take()方法調(diào)用者)。如果沒有任意線程消費(fèi)數(shù)據(jù),transfer方法阻塞。一般用于處理及時(shí)消息。
  • SynchronousQueue : 同步隊(duì)列,容量為0,是特殊的TransferQueue,必須先有消費(fèi)線程等待,才能使用的隊(duì)列。
    • boolean add(E e):父類方法,無阻塞,若沒有消費(fèi)線程阻塞等待數(shù)據(jù),則拋出異常。
    • put(E e):有阻塞,若沒有消費(fèi)線程阻塞等待數(shù)據(jù),則阻塞。

詳細(xì)關(guān)于Queue的介紹,詳見 https://blog.csdn.net/qq_37050329/article/details/116295082

5.2 啟動(dòng)線程

在打開串口的時(shí)候,我們?nèi)?dòng)另一個(gè)線程。這里我使用到了線程池,newSingleExecutor是一個(gè)單線程池,它只會(huì)用唯一的工作線程來執(zhí)行任務(wù),保證所有任務(wù)按照指定順序執(zhí)行。

private val dataQueue = LinkedBlockingQueue<Byte>()
private val singleExecutor: Executor by lazy {
    Executors.newSingleThreadExecutor()
}
private val readRunnable = Runnable {
    //TODO 具體實(shí)現(xiàn)
}
singleExecutor.execute(readRunnable) //啟動(dòng)線程

5.3 定義Cmd用來接收命令

class Cmd {
    companion object {
        const val PREAMBLE: Byte = 0xAA.toByte()
    }

    var preamble: Byte? = null
    var length: Byte = -1
    var payload = ArrayList<Byte>()
    var checkSum: Byte? = null

    fun clear() {
        preamble = null
        length = -1
        payload.clear()
        checkSum = null
    }
}

5.4 進(jìn)行沾包處理

readRunnable中,我們?nèi)プx取dataQueue的數(shù)據(jù),當(dāng)dataQueue沒有數(shù)據(jù)的時(shí)候,會(huì)進(jìn)行阻塞,這樣就避免了性能的損耗。

val byte = dataQueue.take()

接著,如果我們讀到前導(dǎo)幀,就假設(shè)讀取到了一條命令,按順序依次讀取長(zhǎng)度、內(nèi)容校驗(yàn),所有的值都讀取到后,需要對(duì)校驗(yàn)值checkSum做效驗(yàn),具體校驗(yàn)的算法根據(jù)協(xié)議約定來。
命令校驗(yàn)通過后,就可以取到內(nèi)容,轉(zhuǎn)化為Json,進(jìn)一步做業(yè)務(wù)邏輯處理了。

val PREAMBLE: Byte = 0xAA.toByte()
if (byte == PREAMBLE) { //前導(dǎo)幀
    cmd = Cmd()
    cmd.preamble = PREAMBLE
    log("前導(dǎo)幀:0x${HexUtil.toByteString(PREAMBLE)}")
    cmd.length = dataQueue.take()
    log("長(zhǎng)度:${cmd.length}")
    readPayload(dataQueue)
    log("內(nèi)容:${HexUtil.bytesToHexString(cmd.payload.toByteArray())}")
    val checkSum = dataQueue.take()
    cmd.checkSum = checkSum
    log("校驗(yàn):0x${HexUtil.toByteString(checkSum)}")
    //TODO 需要對(duì)checkSum進(jìn)行校驗(yàn),判斷命令是否正確
	val json = String(cmd.payload.toByteArray()) //內(nèi)容轉(zhuǎn)換為Json,這里可以做進(jìn)一步邏輯處理
    cmd.clear()
} else {
    Log.e("Heiko", "被拋棄:0x${HexUtil.toByteString(byte)}")
}

private fun readPayload(dataStack: LinkedBlockingQueue<Byte>) {
    for (i in 0 until cmd.length) {
        cmd.payload.add(dataStack.take())
    }
}

至此,對(duì)于沾包的處理就完成了

6. 附錄

6.1 封裝的串口工具類

附上基于usb-serial-for-android封裝好的串口工具類完整代碼

class UsbSerialManager(
    private val context: Context,
    private val params: UsbSerialParams,
    private val receiver: (String) -> Unit
) :
    SerialInputOutputManager.Listener {
    private var port: UsbSerialPort? = null
    private lateinit var usbIoManager: SerialInputOutputManager
    private val dataQueue = LinkedBlockingQueue<Byte>()
    private var cmd: Cmd = Cmd()
    private val singleExecutor: Executor by lazy {
        Executors.newSingleThreadExecutor()
    }
    private val readRunnable: Runnable
    private val usbManager = context.getSystemService(Context.USB_SERVICE) as UsbManager

    init {
        readRunnable = Runnable {
            while (port?.isOpen == true || dataQueue.isNotEmpty()) {
                val byte = dataQueue.take()
                if (byte == PREAMBLE) { //前導(dǎo)幀
                    cmd = Cmd()
                    cmd.preamble = PREAMBLE
                    log("前導(dǎo)幀:0x${HexUtil.toByteString(PREAMBLE)}")
                    cmd.length = dataQueue.take()
                    log("長(zhǎng)度:${cmd.length}")
                    readPayload(dataQueue)
                    log("payload:${HexUtil.bytesToHexString(cmd.payload.toByteArray())}")
                    val checkSum = dataQueue.take()
                    cmd.checkSum = checkSum
                    log("校驗(yàn):0x${HexUtil.toByteString(checkSum)}")
                    receiver.invoke(String(cmd.payload.toByteArray()))
                    cmd.clear()
                } else {
                    Log.e("Heiko", "被拋棄:0x${HexUtil.toByteString(byte)}")
                }
            }
        }
    }

    private fun readPayload(dataStack: LinkedBlockingQueue<Byte>) {
        for (i in 0 until cmd.length) {
            cmd.payload.add(dataStack.take())
        }
    }

    fun requestPermission() {
        val driver = getDriver() ?: return
        val flags =
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) PendingIntent.FLAG_IMMUTABLE else 0
        val permissionIntent = PendingIntent.getBroadcast(
            context,
            0,
            Intent("com.android.example.USB_PERMISSION"),
            flags
        )
        usbManager.requestPermission(driver.device, permissionIntent)
    }

    private fun getDrivers(): MutableList<UsbSerialDriver> {
        return UsbSerialProber.getDefaultProber().findAllDrivers(usbManager)
    }

    private fun getDriver(): UsbSerialDriver? {
        val availableDrivers = getDrivers()
        if (availableDrivers.isEmpty()) {
            log("availableDrivers is empty.")
            return null
        }

        return availableDrivers[0]
    }

    fun hasPermission(): Boolean {
        val driver = getDriver() ?: return false
        return usbManager.hasPermission(driver.device)
    }

    fun openDevice() {
        if (port?.isOpen == true) {
            log("port is opened.")
            return
        }
        val driver = getDriver() ?: return
        debugLogDrivers()
        val connection = usbManager.openDevice(driver.device) ?: return
        log("connection:$connection")

        port = driver.ports[0] // Most devices have just one port (port 0)
        port?.open(connection)
        port?.setParameters(params.baudRate, params.dataBits, params.stopBits, params.parity)

        usbIoManager = SerialInputOutputManager(port, this)
        usbIoManager.start()
        singleExecutor.execute(readRunnable)

        log("usbIoManager.start")
    }

    private fun debugLogDrivers() {
        if (params.debug) {
            getDrivers().forEach {
                val device = it.device
                log(
                    "deviceId:${device.deviceId} " +
                            " deviceName:${device.deviceName} " +
                            " deviceProtocol:${device.deviceProtocol} " +
                            " productName:${device.productName}" +
                            " productId:${device.productId}" +
                            " manufacturerName:${device.manufacturerName}" +
                            " configurationCount:${device.configurationCount}" +
                            " serialNumber:${device.serialNumber}" +
                            " vendorId:${device.vendorId}"
                )
            }
        }
    }

    fun closeDevice() {
        port?.close()
        port = null
    }

    private fun receive(data: ByteArray?) {
        log("receive:${HexDump.dumpHexString(data)}", "RRRRRRR")

        if (data == null) return
        for (byte in data) {
            dataQueue.put(byte)
        }
    }

    override fun onNewData(data: ByteArray?) {
        receive(data)
    }

    override fun onRunError(e: Exception?) {
        log("onRunError:${e?.message}")
    }

    private fun log(message: String, tag: String = "Heiko") {
        Log.i(tag, message)
    }
}

class Cmd {
    companion object {
        const val PREAMBLE: Byte = 0xAA.toByte()
    }

    var preamble: Byte? = null
    var length: Byte = -1
    var payload = ArrayList<Byte>()
    var checkSum: Byte? = null

    fun clear() {
        preamble = null
        length = -1
        payload.clear()
        checkSum = null
    }
}

6.2 字節(jié)數(shù)組轉(zhuǎn)字符串工具類

附上字節(jié)數(shù)組轉(zhuǎn)字符串工具類

public class HexUtil {
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.equals("")) {
            return null;
        }
        hexString = hexString.toUpperCase();
        int length = hexString.length() / 2;
        char[] hexChars = hexString.toCharArray();
        byte[] d = new byte[length];
        for (int i = 0; i < length; i++) {
            int pos = i * 2;
            d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
        }
        return d;
    }

    private static byte charToByte(char c) {
        return (byte) "0123456789ABCDEF".indexOf(c);
    }

    public static String bytesToHexString(byte[] b) {
        if (b.length == 0) {
            return null;
        }
        StringBuilder sb = new StringBuilder("");
        for (int i = 0; i < b.length; i++) {
            int value = b[i] & 0xFF;
            String hv = Integer.toHexString(value);
            if (hv.length() < 2) {
                sb.append(0);
            }

            sb.append("0x").append(hv).append(" ");
        }
        return sb.toString();
    }

    public static String toByteString(byte b) {
        String hex = Integer.toHexString(b & 0xFF);
        if (hex.length() == 1) {
            hex = '0' + hex;
        }
        return hex.toUpperCase();
    }
}

6.3 UsbSerialParams

UsbSerialParams是一個(gè)參數(shù)配置類,附上代碼文章來源地址http://www.zghlxwxcb.cn/news/detail-415570.html

data class UsbSerialParams(
	var baudRate: Int, //比如 115200
	var dataBits: Int, //比如 8
	var stopBits: Int, //比如 UsbSerialPort.STOPBITS_1
	var parity: Int, //比如 UsbSerialPort.PARITY_NONE
	var debug: Boolean
)

到了這里,關(guān)于Android 沾包處理,以串口接入為例 (usb-serial-for-android)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • LangChain大模型應(yīng)用落地實(shí)踐(二):使用LLMs模塊接入自定義大模型,以ChatGLM為例

    LangChain大模型應(yīng)用落地實(shí)踐(二):使用LLMs模塊接入自定義大模型,以ChatGLM為例

    angChain版本:0.0.147 ;(沒想到第二更LangChain已經(jīng)更新到147了) 圖1 大模型時(shí)間線(2023-arxiv-A Survey of Large Language Models) 模型名稱 企業(yè)/高校 發(fā)布時(shí)間 ERNIE Bot(文心一言) 百度 2023年3月 ChatGLM 清華大學(xué) 2023年3月 通義千問 阿里 2023年4月 MOSS 復(fù)旦大學(xué) 2023年4月 從圖1中可以看出,

    2024年02月09日
    瀏覽(21)
  • 基于瑞芯微平臺(tái)cif接口dvp相機(jī)的視頻接入(ov2640、rv1126為例)

    基于瑞芯微平臺(tái)cif接口dvp相機(jī)的視頻接入(ov2640、rv1126為例)

    CIF,指RK芯片中的VIP模塊,用以接收Sensor數(shù)據(jù)并保存到Memory中,僅轉(zhuǎn)存數(shù)據(jù),無ISP功能 DVP,一種并行數(shù)據(jù)傳輸接口,即Digital Video Port HSYNC,指DVP接口的行同步信號(hào) PCLK,指Sensor輸出Pixel Clock VSYNC,指DVP接口的場(chǎng)同步信號(hào) V4L2,即Video4Linux2,Linux kernel的視頻處理模塊 視頻格式一般

    2024年02月03日
    瀏覽(57)
  • 最佳實(shí)踐 · 塔石串口服務(wù)器接入 MODBUS 物聯(lián)網(wǎng)平臺(tái)

    最佳實(shí)踐 · 塔石串口服務(wù)器接入 MODBUS 物聯(lián)網(wǎng)平臺(tái)

    串口服務(wù)器是為RS-232/RS-485/RS-422終端到TCP/IP之間完成數(shù)據(jù)轉(zhuǎn)換的通訊接口協(xié)議轉(zhuǎn)換器。提供RS-232終端與TCP/IP網(wǎng)絡(luò)的數(shù)據(jù)雙向透明傳輸,提供串口轉(zhuǎn)TCP/IP功能,RS-232/RS-485/RS-422轉(zhuǎn)TCP/IP的解決方案??梢宰孯S-232/RS-485/RS-422串口設(shè)備立即聯(lián)接網(wǎng)絡(luò)。 串口通訊服務(wù)器其實(shí)就是串口服務(wù)器

    2024年02月16日
    瀏覽(25)
  • 【TI毫米波雷達(dá)筆記】UART串口外設(shè)配置及驅(qū)動(dòng)(以IWR6843AOP為例)

    【TI毫米波雷達(dá)筆記】UART串口外設(shè)配置及驅(qū)動(dòng)(以IWR6843AOP為例)

    【TI毫米波雷達(dá)】GPIO初始化、Pinmux引腳復(fù)用和UART串口外設(shè)配置及驅(qū)動(dòng)(以IWR6843AOP為例) 最基本的工程建立好以后 需要給SOC進(jìn)行初始化配置 最是基礎(chǔ)配置模板 包含了時(shí)鐘 MPC DSS BSS上電等等 我這里只用了一個(gè)串口 引腳為: SOC_XWR68XX_PINN4_PADBD 和 SOC_XWR68XX_PINN4_PADBD 另外 配置了

    2024年02月11日
    瀏覽(78)
  • stm32F407學(xué)習(xí)DAY.14 在DMA模式下進(jìn)行USART串口數(shù)據(jù)收發(fā)(正點(diǎn)原子例程為例)

    stm32F407學(xué)習(xí)DAY.14 在DMA模式下進(jìn)行USART串口數(shù)據(jù)收發(fā)(正點(diǎn)原子例程為例)

    目錄 一、DMA配置 1、DMA1和DMA2的請(qǐng)求映射 2、DMA掛載總線 3、DMA相關(guān)庫函數(shù) ?4、DMA配置過程(以串口1為例) 1)進(jìn)行時(shí)鐘使能 2)等待DMA可配置 3)初始化DMA(串口1的TX為DMA2 數(shù)據(jù)流7 通道4,RX為DMA2 數(shù)據(jù)流5?通道4) a.DMA外設(shè)地址par: b.DMA存儲(chǔ)器0地址mar: c.數(shù)據(jù)傳輸量ndtr: 4)

    2024年02月04日
    瀏覽(22)
  • 2022最新Android項(xiàng)目導(dǎo)入過程(以Android studio2021.2.1為例)

    2022最新Android項(xiàng)目導(dǎo)入過程(以Android studio2021.2.1為例)

    當(dāng)我們?cè)L問別人項(xiàng)目的時(shí)候,可能由于別人項(xiàng)目版本太老,總是導(dǎo)入不了。常常報(bào)出如下錯(cuò)誤。 也就是Android Studio版本不支持。我們通常需要修改一些配置信息才能正確導(dǎo)入。 常見的Android項(xiàng)目結(jié)構(gòu)如圖。 【注釋】打開類型如圖 打開Android studio,新建安卓項(xiàng)目。待自動(dòng)導(dǎo)入完

    2024年02月05日
    瀏覽(23)
  • android支付寶接入流程

    android支付寶接入流程

    接入APP支付能力前,開發(fā)者需要完成以下前置步驟。 本文檔展示了如何從零開始,使用支付寶開放平臺(tái)服務(wù)端 SDK 快速接入App支付產(chǎn)品,完成與支付寶對(duì)接的部分。 要在您的應(yīng)用中接入支付寶 App 支付能力,您需要登錄支付寶開放平臺(tái)open.alipay.com),在開發(fā)者中心中創(chuàng)建您的

    2024年04月13日
    瀏覽(13)
  • android amazon 支付接入

    流程: 申請(qǐng) Amazon 開發(fā)者帳號(hào) --- 在 amazon 控制臺(tái)添加應(yīng)用 --- 添加應(yīng)用內(nèi)商品(消費(fèi)類商品,授權(quán)類商品,訂閱類商品)--- 導(dǎo)出 JSON 文件 ---集成 Amazon 支付 --- 將導(dǎo)出的 JSON 文件 copy 到 /mnt/sdcard/目錄下--- 沙河模式下測(cè)試支付?--- 上傳發(fā)布 注意:亞馬遜目前使用 V1 簽名;2.

    2024年02月11日
    瀏覽(38)
  • 以ChatGPT為例進(jìn)行自然語言處理學(xué)習(xí)——入門自然語言處理

    以ChatGPT為例進(jìn)行自然語言處理學(xué)習(xí)——入門自然語言處理

    ??我叫憶_恒心,一名喜歡書寫博客的在讀研究生?????。 如果覺得本文能幫到您, 麻煩點(diǎn)個(gè)贊 ??唄! 近期會(huì)不斷在專欄里進(jìn)行更新講解博客~~~ 有什么問題的小伙伴 歡迎留言提問歐,喜歡的小伙伴給個(gè)三連支持一下唄。?????? Qt5.9專欄 定期更新Qt的一些項(xiàng)目Demo

    2023年04月23日
    瀏覽(39)
  • Android平臺(tái)GB28181設(shè)備接入端如何實(shí)現(xiàn)多視頻通道接入?

    Android平臺(tái)GB28181設(shè)備接入端如何實(shí)現(xiàn)多視頻通道接入?

    技術(shù)背景 我們?cè)谠O(shè)計(jì)Android平臺(tái)GB28181設(shè)備接入模塊的時(shí)候,有這樣的場(chǎng)景訴求,一個(gè)設(shè)備可能需要多個(gè)通道,常見的場(chǎng)景,比如車載終端,一臺(tái)設(shè)備,可能需要接入多個(gè)攝像頭,那么這臺(tái)車載終端設(shè)備可以作為主設(shè)備,然后,主設(shè)備下,配置多個(gè)通道,聽起來是不是有點(diǎn)兒類

    2024年02月13日
    瀏覽(26)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包