在Android 開發中,我們多多少少都會接觸到NDK開發,下面就倆講一下NDk的開發流程
1、定義一個普通的Java類 ↓,然後編寫native本地方法;
package com.xykj.imp;
public class JniUtil {
public static native int add(int a,int b);public static native String sayHello();
}
2、將javac文件轉爲class文件,使用javac指令
(如:文件位置為 D:\AT31\AndroidCode\Lesson19_JNI\src\com\xykj\imp\JniUtil.java)
進入:D:\AT31\AndroidCode\Lesson19_JNI\src\com\xykj\imp>
使用:javac JniUtil.java
回車之後得到 class文件,在方法中刷新一下便可得到,
3、將class文件轉爲.h文件,需要回到源碼路徑下(src路徑下)
D:\AT31\AndroidCode\Lesson19_JNI\src>
使用javah命令: javah -d ../jni/ com.xykj.imp.JniUtil (注意中間用空格分開)
-d表示將編譯結果放到一個目標目錄下(../jni/)
h文件中jni方法的結果
每個方法均有JNIEXPORT關鍵字,然後有jni返回值類型,然後JNICALL關聯要實現的java本地方法
JNIEXPORT jint JNICALL Java_com_xykj_imp_JniUtil_add(JNIEnv *, jclass, jint, jint);
c功能實現文件
1,複製一個.h文件:
引入要實現的頭文件
#include "JniUtil.h"
/*
* Class: com_xykj_imp_JniUtil
* Method: add
* Signature: (II)I
*/
JNIEXPORT jint JNICALL Java_com_xykj_imp_JniUtil_add
(JNIEnv *env, jclass obj, jint a, jint b){
// char buf[150];
// sprintf(buf,"value of a:%d b:%d",a,b);
// __android_log_print(ANDROID_LOG_INFO,"m_tag",buf); //Log.i("m_tag","value of a:5 b:10");
return a+b;
}
/*
* Class: com_xykj_imp_JniUtil
* Method: sayHello
* Signature: ()Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_com_xykj_imp_JniUtil_sayHello
(JNIEnv *env, jclass obj){
return (*env)->NewStringUTF(env,"Hello jni");
}
編寫mk文件
要在c文件的同目錄下,創建一個Android.mk文件,配置編譯的庫名稱,以及編譯需要的c文件
LOCAL_PATH:= $(call my-dir)
#LOCAL_CPP_EXTENSION := .cpp
include $(CLEAR_VARS)
LOCAL_PRELINK_MODULE := false
LOCAL_MODULE := hellojni
LOCAL_SRC_FILES := JniUtil.c
LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog
#LOCAL_STATIC_LIBRARIES :=
#LOCAL_SHARED_LIBRARIES :=
include $(BUILD_SHARED_LIBRARY)
編譯so文件
1、首先看看你的環境變量裏有沒有配置ndk,沒有就先將ndk的根目錄配置到系統環境變量的path路徑下
2、cmd,dos界面進入項目根目錄下(如: D:\AT31\AndroidCode\Lesson19_JNI )
3、使用ndk-build命令編譯
D:\AT31\AndroidCode\Lesson19_JNI>ndk-build
使用so
在java中任何地方定義靜態 區
// 加载动态 so 库
static{
System.loadLibrary("hellojni");
}
在java中調用native
int c = JniUtil.add(156, 7894);
String str = JniUtil.sayHello();
tv.setText("156+7894="+c+" \n"+str);
自定義ContentProvider
1、定義一個ContentProvider類管理數據庫,實現對數據表的增刪改查方法
public class MyProvider extends ContentProvider {
重写 onCreate() query() insert() update() delete()
}
2、在mainfest中注冊ContentProvider
<provider
android:name="com.xykj.providerdemo.MyProvider"
android:authorities="com.xykj.providerdemo"
android:exported="true" >
</provider>
注意:android:authorities表示注冊的Uri的唯一標識
3、在ContentProvider中添加功能Uri,一般一個表分兩類,一類是多條操作,一類是單條操作
// Uri 功能校验码
private static final int TYPE_MORE = 1; // 多条操作,针对的目标是表
private static final int TYPE_ITEM = 2; // 单条操作,针对的木目标是一个确定的 item( 用 id 来确定 )
private static final UriMatcher mMatcher;
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 添加一个 Uri-->content://com.xykj.providerdemo/all --> 1
mMatcher.addURI("com.xykj.providerdemo", "all", TYPE_MORE);
// 添加一个 Uri-->content://com.xykj.providerdemo/all/# --> 2
mMatcher.addURI("com.xykj.providerdemo", "all/#", TYPE_ITEM);
}
4、 基於Uri實現各個功能 方法
package com.xykj.providerdemo;
import android.content.ContentProvider;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.UriMatcher;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import android.database.sqlite.SQLiteQueryBuilder;
import android.net.Uri;
public class MyProvider extends ContentProvider {
private static final String DB_NAME = "mydb.db";
private static final int VERSION = 1;
// 日记表的表名
private static final String TB_DIARY = "diary";
// Uri 功能校验码
private static final int TYPE_MORE = 1; // 多条操作,针对的目标是表
private static final int TYPE_ITEM = 2; // 单条操作,针对的木目标是一个确定的 item( 用 id 来确定 )
private DbOpenHelper mHelper;
private SQLiteDatabase mDb;
private static final UriMatcher mMatcher;
static {
mMatcher = new UriMatcher(UriMatcher.NO_MATCH);
// 添加一个 Uri-->content://com.xykj.providerdemo/all --> 1
mMatcher.addURI("com.xykj.providerdemo", "all", TYPE_MORE);
// 添加一个 Uri-->content://com.xykj.providerdemo/all/# --> 2
mMatcher.addURI("com.xykj.providerdemo", "all/#", TYPE_ITEM);
}
/**
* Provider 创建成功时触发(安装到系统,第一次被使用时)
*/
@Override
public boolean onCreate() {
mHelper = new DbOpenHelper(getContext());
mDb = mHelper.getWritableDatabase();
return true;
}
/**
* 收到 ContentResolver 的 query 查询时触发
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection,
String[] selectionArgs, String sortOrder) {
SQLiteQueryBuilder sqb = new SQLiteQueryBuilder();
switch (mMatcher.match(uri)) {
case TYPE_MORE:
// 处理多条的查询
sqb.setTables(TB_DIARY);
break;
case TYPE_ITEM:
// 处理单条数据的查询
sqb.setTables(TB_DIARY);
// 取出 # 的内容 item #
String str = uri.getPathSegments().get(1);
// 将 # 内容当做 id 作为单条操作的条件
sqb.appendWhere("_id=" + str);
break;
}
Cursor c = sqb.query(mDb, projection, selection, selectionArgs, null,
null, sortOrder);
return c;
}
/**
* 针对每个期望的 Uri 定义一个类型 (mime 类型 )
*/
@Override
public String getType(Uri uri) {
switch (mMatcher.match(uri)) {
case TYPE_MORE:
return "vnd.android.cusor.dir/all";
case TYPE_ITEM:
return "vnd.android.cusor.item/item";
}
return null;
}
/**
* 收到 ContentResolver 的 insert 查询时触发
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
// 希望插入数据的目标是一个表 ( 没有具体 id 的指定 )
if(mMatcher.match(uri) != TYPE_MORE){
throw new IllegalArgumentException(" 非法的 Uri:"+uri);
}
//id 为 5
long raw = mDb.insert(TB_DIARY, null, values);
// content://com.xykj.providerdemo/all/5
if(raw>0){
// 插入成功 , 拼接该条数据的 uri
return ContentUris.withAppendedId(uri, raw);
}
return null;
}
/**
* 收到 ContentResolver 的 delete 查询时触发
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
/**
* 收到 ContentResolver 的 update 查询时触发
*/
@Override
public int update(Uri uri, ContentValues values, String selection,
String[] selectionArgs) {
// TODO Auto-generated method stub
return 0;
}
class DbOpenHelper extends SQLiteOpenHelper {
public DbOpenHelper(Context context) {
super(context, DB_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
String sql = "create table "
+ TB_DIARY
+ " (_id integer primary key autoincrement,title text,content text)";
db.execSQL(sql);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
}
使用 端使用ContentResolve來訪問
Uri uri = Uri.parse("content://com.xykj.providerdemo/all");
// 插入数据
ContentValues values = new ContentValues();
values.put("title", "android");
values.put("content", "abc12345");
Uri iUri1 = getContentResolver().insert(uri, values);
String[] projection = { "_id", "title", "content" };
// 多条查询
Cursor c = getContentResolver()
.query(uri, projection, null, null, null);
while (c.moveToNext()) {
int id = c.getInt(0);
String title = c.getString(1);
String content = c.getString(2);
Log.e("m_tag", "id:" + id + " title:" + title + "\tcontent:"
+ content);
}
c.close();
// 单条查询
// 查询
Uri uri2 = Uri.parse("content://com.xykj.providerdemo/all/2");
Cursor c1 = getContentResolver().query(uri2, projection, null, null,
null);
while (c1.moveToNext()) {
int id = c1.getInt(0);
String title = c1.getString(1);
String content = c1.getString(2);
Log.e("m_tag", "id:" + id + " title:" + title + "\tcontent:"
+ content);
}
c1.close();
Uri的特殊的操作
Uri 中获取子路径内容
// 取出 # 的内容 item #
String str = uri.getPathSegments().get(1);
Uri 后拼接内容 ( 拼接 id)
Uri nUri = ContentUris.withAppendedId(uri, raw);