Android開(kāi)發(fā)中,經(jīng)常會(huì)在Java代碼與Jni層之間傳遞數(shù)組(byte[]),一個(gè)典型的應(yīng)用是Java層把需要發(fā)送給客戶(hù)端的數(shù)據(jù)流傳遞到Jni層,由Jni層的Socket代碼發(fā)送出去,當(dāng)然,Jni層也需要把從Socket接收到的數(shù)據(jù)流返回給Java層。我簡(jiǎn)單地總結(jié)了一下,從Java層到Jni層,從Jni層到JAVA層,各有3種傳遞方式,下面用代碼示例簡(jiǎn)單地介紹一下。
創(chuàng)新互聯(lián)于2013年成立,先為江南等服務(wù)建站,江南等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為江南企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。示例代碼的主要文件有兩個(gè),一個(gè)是Native.java,是Java層的類(lèi);另一個(gè)是Native.c,是JNI層的文件,關(guān)鍵的地方我都用注釋添加到代碼中了,完整的代碼見(jiàn)博文后面的附件。
一、 從Java傳遞數(shù)組到Jni層
Jni層接收到Java層傳遞過(guò)來(lái)的byte[]數(shù)組,一般有2個(gè)函數(shù)來(lái)獲取它的值,一個(gè) GetByteArrayRegion,另一個(gè)是 GetByteArrayElements ,前者是進(jìn)行值拷貝,將Java端數(shù)組的數(shù)據(jù)拷貝到本地的數(shù)組中,后者是指針的形式,將本地的數(shù)組指針直接指向Java端的數(shù)組地址,其實(shí)本質(zhì)上是JVM在堆上分配的這個(gè)數(shù)組對(duì)象上增加一個(gè)引用計(jì)數(shù),保證垃圾回收的時(shí)候不要釋放,從而交給本地的指針使用,使用完畢后指針一定要記得通過(guò)ReleaseByteArrayElements進(jìn)行釋放,否則會(huì)產(chǎn)生內(nèi)存泄露。
首先看Native.java的定義:
再看看對(duì)應(yīng)的native.c的實(shí)現(xiàn)代碼:
二、 從Jni層傳遞數(shù)組到Java層
把Jni層定義的數(shù)組傳遞到Java層,一般有兩種方法,一種是通過(guò)native函數(shù)的返回值來(lái)傳遞,另一種是通過(guò)jni層回調(diào)java層的函數(shù)來(lái)傳遞,后者多用于jni的線(xiàn)程中。無(wú)論哪種方法,都離不開(kāi) SetByteArrayRegion 函數(shù),該函數(shù)將本地的數(shù)組數(shù)據(jù)拷貝到了 Java 端的數(shù)組中。下面只介紹前一種方式,即通過(guò)native函數(shù)返回值的方式傳遞jni層的數(shù)組,回調(diào)的方式其實(shí)用法類(lèi)似,就不詳細(xì)介紹了。
首先看Native.java的定義:
再看看native.c是如何實(shí)現(xiàn)的:
由上述代碼示例可以看出,首先通過(guò) NewByteArray 在堆上分配數(shù)組對(duì)象,然后通過(guò)SetByteArrayRegion 把本地的數(shù)組數(shù)據(jù)拷貝到堆上分配的數(shù)組中去,然后通過(guò)返回值將分配的數(shù)組對(duì)象返回到Java層即可。對(duì)于回調(diào)的方式,這幾步操作也是一樣的,唯一的不同是,回調(diào)方式不是以返回值的方式將數(shù)組對(duì)象返回給Java層,而是在回調(diào)函數(shù)中,以回調(diào)函數(shù)參數(shù)的形式返回給Java層。
三、 Direct Buffer 方式傳遞
Java和Jni層的數(shù)組傳遞還有一個(gè)比較重要的方式,就是通過(guò)Direct Buffer來(lái)傳遞,這種方式類(lèi)似于在堆上創(chuàng)建創(chuàng)建了一個(gè)Java和Jni層共享的整塊內(nèi)存區(qū)域,無(wú)論是Java層或者Jni層均可訪(fǎng)問(wèn)這塊內(nèi)存,并且Java端與Jni端同步變化,由于是采用的是共享內(nèi)存的方式,因此相比于普通的數(shù)組傳遞,效率更高,但是由于構(gòu)造/析構(gòu)/維護(hù)這塊共享內(nèi)存的代價(jià)比較大,所以小數(shù)據(jù)量的數(shù)組建議還是采用上述方式,Direct Buffer方式更適合長(zhǎng)期使用頻繁訪(fǎng)問(wèn)的大塊內(nèi)存的共享。具體使用方法介紹如下:
首先看Native.java的定義:
再看看native.c是如何實(shí)現(xiàn)的:
由上述代碼可以看出,其中使用起來(lái)還是很簡(jiǎn)單的,Jni層只需要通過(guò)GetDirectBufferAddress函數(shù)即可獲取到這塊共享的內(nèi)存的地址,Direct Buffer的管理工作均由操作系統(tǒng)來(lái)負(fù)責(zé)。
四、 總結(jié)
關(guān)于Java與Jni層的數(shù)組傳遞就介紹到這里了,其實(shí)并不復(fù)雜,希望上述代碼對(duì)初學(xué)者能有所幫助,有任何疑問(wèn)或者不清楚的地方歡迎留言或者來(lái)信lujun.hust@gmail.com交流,或者關(guān)注我的新浪微博 @盧_俊 獲取最新的文章和資訊。
附件:http://down.51cto.com/data/2364072另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線(xiàn),公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。