android上 kotlin 和jni的混合使用

前言

本文探討一下kotlin和jni的混合使用,綜合考慮市殷,jni的入口函數(shù)采用java編程,其他的android業(yè)務(wù)邏輯采用kotlin編程。c程序內(nèi)容是自己在ubuntu環(huán)境下編譯so文件導(dǎo)入工程實(shí)現(xiàn)代碼安全躬充。
這個(gè)ui是用來控制開發(fā)板的led的,這里把控制led的代碼改為普通的日志輸出讨便,不影響普通的使用

1充甚、 UI布局

直接把xml文件貼出來,只是測試demo霸褒,寫的比較隨便
布局里面 就是按鈕和checkbox

<?xml version="1.0" encoding="utf-8"?>
<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"
    android:orientation="vertical"
    tools:context="com.example.act64.myapplication.MainActivity"
    tools:layout_editor_absoluteX="0dp"
    tools:layout_editor_absoluteY="81dp">

    <TextView
        android:id="@+id/sample_text"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="Hello World!"
        app:layout_constraintBottom_toTopOf="@+id/button"
        app:layout_constraintHorizontal_bias="0.097"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0" />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal"
        android:id="@+id/all_btn"
        android:text="All ON/OFF" />

    <CheckBox
        android:id="@+id/led1"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp"
        android:text="LED1" />

    <CheckBox
        android:id="@+id/led2"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp"
        android:text="LED2" />

    <CheckBox
        android:id="@+id/led3"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp"
        android:text="LED3" />

    <CheckBox
        android:id="@+id/led4"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginBottom="5dp"
        android:text="LED4" />

</LinearLayout>

2伴找、Activity

要使用kt的話,gradle要先配好傲霸,可以看我之前的博客
<a href="http://www.reibang.com/p/f599305e1022">kotlin + retroft+rxjava查詢天氣</a>
demo只有一個(gè)Activity,里面有些kotlin的語法

  • import kotlinx.android.synthetic.main.activity_main.*

這是kotlin的androidUI擴(kuò)展疆瑰,需要gradle配置好了以后才能用,功能就是可以用控件的UI名直接訪問UI控件昙啄,不需要findviewById了穆役,當(dāng)然用了findviewById也不會(huì)出錯(cuò)了

  • setOnClickListener{// todo...}

這個(gè)就等價(jià)于

setOnClickListener(new  OnClickListener(){
onclick(View v){
// todo...
}  
})

setOnCheckedChangeListener也是類似

  • 數(shù)組的一些操作

構(gòu)造boolean類型數(shù)組

  private var lightsState:BooleanArray = BooleanArray(4,{ false})

判斷是否全為true

if (lightsState.all { i->i })

將所有值設(shè)為true

 lightsState.fill( true )

其他也沒啥了,完整的代碼如下


package com.example.act64.myapplication

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import android.widget.TextView
import com.example.act64.myapplication.control.HardControl
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    private var lightsState:BooleanArray = BooleanArray(4,{ false})

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

        // Example of a call to a native method
        val tv = findViewById(R.id.sample_text) as TextView

        all_btn.setOnClickListener {
            if (lightsState.all { i->i }){
                lightsState.fill(false)
                HardControl.LedClose()

            }else{
                lightsState.fill( true )
                HardControl.LedOpen()
            }
            applyUIFromArray()
        }
        led1.setOnCheckedChangeListener({buttonView, isChecked ->
            lightsState[0]=isChecked
            HardControl.LedControl(0,if (isChecked)1 else 0)
        })
        led2.setOnCheckedChangeListener({buttonView, isChecked ->
            lightsState[1]=isChecked
            HardControl.LedControl(1,if (isChecked)1 else 0)
        })
        led3.setOnCheckedChangeListener({buttonView, isChecked ->
            lightsState[2]=isChecked
            HardControl.LedControl(2,if (isChecked)1 else 0)
        })
        led4.setOnCheckedChangeListener({buttonView, isChecked ->
            lightsState[3]=isChecked
            HardControl.LedControl(3,if (isChecked)1 else 0)

        })

    }

    fun applyUIFromArray(){
        led1.isChecked=lightsState[0]
        led2.isChecked=lightsState[1]
        led3.isChecked=lightsState[2]
        led4.isChecked=lightsState[3]

    }


}

3梳凛、 Jni部分

考慮編譯方便耿币,jni部分還是用java+c的方式,主要是javah方式可以生成需要的參數(shù)返回值和字段描述符韧拒,比較適合新手使用淹接,當(dāng)然可以用androidstudio 3.0自帶的快捷鍵將java轉(zhuǎn)為kt,需要的直接百度叛溢、google

先是 java

package com.example.act64.myapplication.control;

/**
 * Created by act64 on 2017/6/3.
 */

public class HardControl {
    static {
        System.loadLibrary("hardcontrol");
    }

    public static native int LedOpen();
    public static native int LedClose();
    public static native int LedControl(int ledWitch,int status);
}

然后可以生成 javah文件了塑悼,具體怎么弄可以去看我之前的文章或者白底,我用的指令如下
先cd 到j(luò)ava目錄
然后

javac com/example/act64/myapplication/control/HardControl.java

javah -jni com.example.act64.myapplication.control.HardControl

這樣對(duì)應(yīng)的.h文件生成了楷掉,然后寫對(duì)應(yīng)的c文件厢蒜,我這里命名為
hardcontrol.c

#include <stdio.h>
#include <jni.h>
//引用了log.h 打印日志包
#include <android/log.h>
#define LOG_TAG "Ledtest"
#define   LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)

 jint  c_LedOpen(JNIEnv * env, jclass cls){
     LOGE("led Open");
     return 1;
 }

 jint c_LedClose(JNIEnv * env, jclass cls){
       LOGE("led Close");
     return 1;
 }
jint c_LedControl(JNIEnv * env, jclass cls, jint which, jint status){
      LOGE("led %d status = %d",which,status);
    return 1;
}

//這是jni.h提供的方法映射結(jié)構(gòu)體,用于映射
//java方法和c方法
//三個(gè)參數(shù)為 java函數(shù)名 , 描述符,和c的函數(shù)指針
const JNINativeMethod methods[]={
    {"LedOpen","()I",(jint *)c_LedOpen},
     {"LedClose","()I",(jint *)c_LedClose},
     {"LedControl","(II)I",(jint *)c_LedControl},
};

//此JNI_OnLoad是系統(tǒng)函數(shù)
//當(dāng)java loadlibrary時(shí)會(huì)自動(dòng)調(diào)用
//
JNIEXPORT jint JNICALL
JNI_OnLoad(JavaVM *jvm, void *reserved)
{
JNIEnv *env;
jclass cls;
//獲得context,并且取得目標(biāo)java類
if ((*jvm)->GetEnv(jvm, (void **)&env, JNI_VERSION_1_4)) {
return JNI_ERR; /* JNI version not supported */
}
cls = (*env)->FindClass(env, "com/example/act64/myapplication/control/HardControl");
if (cls == NULL) {
return JNI_ERR;
}
//將java方法和對(duì)應(yīng)的c方法映射,第四個(gè)參數(shù)是映射的條數(shù)
if((*env)->RegisterNatives(env,cls,methods,3)<0){
    return JNI_ERR;
}
return JNI_VERSION_1_4;
}

4、編譯

先編譯so文件
里面include的路徑 libc.so和liblog.so的路徑需要指向自己的哦

arm-linux-gcc -fPIC -I /usr/lib/jvm/java-1.7.0-openjdk-amd64/include  -I /data4/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/include -shared -o libhardcontrol.so  hardcontrol.c -nostdlib /data4/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/libc.so  /data4/android-5.0.2/prebuilts/ndk/9/platforms/android-19/arch-arm/usr/lib/liblog.so 

然后我們就能得到libhardcontrol.so烹植,把它弄到android目錄里面斑鸦,
放在libs目錄下的armeabi目錄下,這里armeabi目錄可能需要自己建一個(gè)草雕,因?yàn)橹暗木幾g指令是支持arm的巷屿,所有生成的so文件要放在這個(gè)下面。然后改對(duì)應(yīng)module下的gradle墩虹,加入

sourceSets{
        main {
            jniLibs.srcDirs = ["libs"]
        }
    }

完整gradle如下

apply plugin: 'com.android.application'

apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'


android {
    compileSdkVersion 25
    buildToolsVersion "25.0.3"
    defaultConfig {
        applicationId "com.example.act64.myapplication"
        minSdkVersion 15
        targetSdkVersion 25
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

    }
    sourceSets{
        main {
            jniLibs.srcDirs = ["libs"]
        }
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}

dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
    compile 'com.android.support:appcompat-v7:25.3.1'
    testCompile 'junit:junit:4.12'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
}

然后執(zhí)行編譯裝到手機(jī)上點(diǎn)點(diǎn)看
輸出如下內(nèi)容

輸出內(nèi)容
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末嘱巾,一起剝皮案震驚了整個(gè)濱河市憨琳,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌浓冒,老刑警劉巖栽渴,帶你破解...
    沈念sama閱讀 218,204評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異稳懒,居然都是意外死亡闲擦,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門场梆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來墅冷,“玉大人,你說我怎么就攤上這事或油∧蓿” “怎么了?”我有些...
    開封第一講書人閱讀 164,548評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵顶岸,是天一觀的道長腔彰。 經(jīng)常有香客問我,道長辖佣,這世上最難降的妖魔是什么霹抛? 我笑而不...
    開封第一講書人閱讀 58,657評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮卷谈,結(jié)果婚禮上杯拐,老公的妹妹穿的比我還像新娘。我一直安慰自己世蔗,他們只是感情好端逼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,689評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著污淋,像睡著了一般顶滩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上寸爆,一...
    開封第一講書人閱讀 51,554評(píng)論 1 305
  • 那天诲祸,我揣著相機(jī)與錄音,去河邊找鬼而昨。 笑死,一個(gè)胖子當(dāng)著我的面吹牛找田,可吹牛的內(nèi)容都是我干的歌憨。 我是一名探鬼主播,決...
    沈念sama閱讀 40,302評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼墩衙,長吁一口氣:“原來是場噩夢啊……” “哼务嫡!你這毒婦竟也來了甲抖?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,216評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤心铃,失蹤者是張志新(化名)和其女友劉穎准谚,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體去扣,經(jīng)...
    沈念sama閱讀 45,661評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡柱衔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,851評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了愉棱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片唆铐。...
    茶點(diǎn)故事閱讀 39,977評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖奔滑,靈堂內(nèi)的尸體忽然破棺而出艾岂,到底是詐尸還是另有隱情,我是刑警寧澤朋其,帶...
    沈念sama閱讀 35,697評(píng)論 5 347
  • 正文 年R本政府宣布王浴,位于F島的核電站,受9級(jí)特大地震影響梅猿,放射性物質(zhì)發(fā)生泄漏氓辣。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,306評(píng)論 3 330
  • 文/蒙蒙 一粒没、第九天 我趴在偏房一處隱蔽的房頂上張望筛婉。 院中可真熱鬧,春花似錦癞松、人聲如沸爽撒。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽硕勿。三九已至,卻和暖如春枫甲,著一層夾襖步出監(jiān)牢的瞬間源武,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評(píng)論 1 270
  • 我被黑心中介騙來泰國打工想幻, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留粱栖,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,138評(píng)論 3 370
  • 正文 我出身青樓脏毯,卻偏偏與公主長得像闹究,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子食店,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,927評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容