本机方法中的UnsatisfiedLinkError

时间:2014-02-04 11:16:31

标签: android c++ java-native-interface android-sqlite unsatisfiedlinkerror

我在本机方法中得到了不满意的链接错误

Logcat主要异常

UnsatisfiedLinkError: Native method not found: rg.sqlite.database.sqlite.SQLiteConnection.nativeHasCodec:()Z

完成Logcat

02-04 16:29:12.807: E/AndroidRuntime(5087): FATAL EXCEPTION: main
02-04 16:29:12.807: E/AndroidRuntime(5087): java.lang.UnsatisfiedLinkError: Native method not found: org.sqlite.database.sqlite.SQLiteConnection.nativeHasCodec:()Z
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteConnection.nativeHasCodec(Native Method)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteConnection.hasCodec(SQLiteConnection.java:160)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteDatabase.hasCodec(SQLiteDatabase.java:2195)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteConnectionPool.setMaxConnectionPoolSizeLocked(SQLiteConnectionPool.java:952)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteConnectionPool.<init>(SQLiteConnectionPool.java:153)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteConnectionPool.open(SQLiteConnectionPool.java:179)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteDatabase.openInner(SQLiteDatabase.java:804)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteDatabase.open(SQLiteDatabase.java:789)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:694)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at org.sqlite.database.sqlite.SQLiteDatabase.openDatabase(SQLiteDatabase.java:669)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at com.example.samplesqlitedb.SearchDataDB.getAutoSuggestion(SearchDataDB.java:33)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at com.example.samplesqlitedb.MainActivity$2.onClick(MainActivity.java:56)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.view.View.performClick(View.java:4084)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.view.View$PerformClick.run(View.java:16966)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.os.Handler.handleCallback(Handler.java:615)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.os.Handler.dispatchMessage(Handler.java:92)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.os.Looper.loop(Looper.java:137)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at android.app.ActivityThread.main(ActivityThread.java:4745)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at java.lang.reflect.Method.invokeNative(Native Method)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at java.lang.reflect.Method.invoke(Method.java:511)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
02-04 16:29:12.807: E/AndroidRuntime(5087):     at dalvik.system.NativeStart.main(Native Method)

自定义Java文件SQLiteConnection      https://www.dropbox.com/s/5ex6u9rzkwb7kqq/SQLiteConnection.java 错误在线号码160

这是源cpp文件,我编译并创建了二进制“libsqliteX.so”文件http://www.sqlite.org/android/tree?ci=trunk&re=jni|src/org/sqlite/data&expand

我的.so文件https://www.dropbox.com/s/d0u5pyhke54tcd6/libsqliteX.so

所以我认为我必须在本机方法中修改以解决此问题

static jboolean nativeHasCodec(JNIEnv* env, jobject clazz){
#ifdef SQLITE_HAS_CODEC
return true;
#else
return false;
#endif
}

这是CDT GLOBAL BUILD CONSOLE

**** Build of configuration Default for project CustomSqlite ****

D:\software\adt-bundle-windows-x86-20130522\adt-bundle-windows-x86-20130522\android-ndk-r9-windows-x86\android-ndk-r9\ndk-build.cmd all 
"Compile++ thumb : sqliteX <= android_database_SQLiteCommon.cpp
"Compile++ thumb : sqliteX <= android_database_SQLiteConnection.cpp
"Compile++ thumb : sqliteX <= android_database_SQLiteGlobal.cpp
"Compile++ thumb : sqliteX <= android_database_SQLiteDebug.cpp
"Compile++ thumb : sqliteX <= JNIHelp.cpp
"Compile++ thumb : sqliteX <= JniConstants.cpp
"Compile thumb : sqliteX <= sqlite3.c
SharedLibrary  : libsqliteX.so
Install        : libsqliteX.so => libs/armeabi/libsqliteX.so

**** Build Finished ****

**** Build of configuration Default for project CustomSqlite ****

D:\software\adt-bundle-windows-x86-20130522\adt-bundle-windows-x86-20130522\android-ndk-r9-windows-x86\android-ndk-r9\ndk-build.cmd all 
Install        : libsqliteX.so => libs/armeabi/libsqliteX.so

**** Build Finished ****

所以我认为.so是正确生成的

这是我的Customsqlite.java

它有方法

package org.sqlite.app.customsqlite;

import java.io.File;
import java.io.FileInputStream;
import java.util.ArrayList;
import java.util.Arrays;
import org.sqlite.database.DatabaseErrorHandler;
import org.sqlite.database.sqlite.SQLiteDatabase;
import org.sqlite.database.sqlite.SQLiteOpenHelper;
import org.sqlite.database.sqlite.SQLiteStatement;
import android.app.Activity;
import android.content.Context;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.EditText;
import android.widget.TextView;

class DoNotDeleteErrorHandler implements DatabaseErrorHandler {
private static final String TAG = "DoNotDeleteErrorHandler";
public void onCorruption(SQLiteDatabase dbObj) {
    Log.e(TAG,"Corruption reported by sqlite on database: " + dbObj.getPath());
}
}

public class CustomSqlite extends Activity {
private TextView myTV;  
EditText query;
File DB_PATH;
String searchedword;

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);
    myTV = (TextView) findViewById(R.id.tv_widget);
    query = (EditText) findViewById(R.id.query);
}

public void report_version() {
    SQLiteDatabase db = null;
    SQLiteStatement st;
    String res;

    db = SQLiteDatabase.openOrCreateDatabase(":memory:", null);
    st = db.compileStatement("SELECT sqlite_version()");
    res = st.simpleQueryForString();

    myTV.append("SQLite version " + res + "\n\n");
}

public void test_warning(String name, String warning) {
    myTV.append("WARNING:" + name + ": " + warning + "\n");
}

public void test_result(String name, String res, String expected) {
    myTV.append(name + "... ");


    if (res.equals(expected)) {
        myTV.append("ok\n");
    } else {

        myTV.append("FAILED\n");
        myTV.append("   res=     \"" + res + "\"\n");
        myTV.append("   expected=\"" + expected + "\"\n");
    }
}

/*
 * * Test if the database at DB_PATH is encrypted or not. The db* is assumed
 * to be encrypted if the first 6 bytes are anything* other than "SQLite".**
 * If the test reveals that the db is encrypted, return the string*
 * "encrypted". Otherwise, "unencrypted".
 */
public String db_is_encrypted() throws Exception {
    FileInputStream in = new FileInputStream(DB_PATH);
    byte[] buffer = new byte[6];
    in.read(buffer, 0, 6);
    String res = "encrypted";
    if (Arrays.equals(buffer, (new String("SQLite")).getBytes())) {
        res = "unencrypted";
    }
    in.close();
    return res;
}

/*
 * * Use a Cursor to loop through the results of a SELECT query.
 */
public void syno() throws Exception {
    DB_PATH = new File("/storage/sdcard1/sk2.db");
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
    Cursor c = db.rawQuery("SELECT synsetid, w2.lemma FROM sense LEFT JOIN word AS w2 ON w2.wordid=sense.wordid WHERE sense.synsetid IN (SELECT sense.synsetid FROM word AS w1 LEFT JOIN sense ON w1.wordid=sense.wordid WHERE w1.lemma='"+ searchedword+ "') AND w2.lemma<>'"+ searchedword + "'", null);
    ArrayList<String> list1 = new ArrayList<String>();
    if (c != null) {

        if (c.getCount() > 0) {
            c.moveToFirst();
            do {
                list1.add(c.getString(1));
            } while (c.moveToNext());

            }
        myTV.append("\n\nSYNONYM " + list1.toString());
    }



    db.close();

}

/*
 * * If this is a SEE build, check that encrypted databases work.
 */
public void anto() throws Exception {

SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
    Cursor c = db.rawQuery("SELECT DISTINCT(w2.lemma) as lemma from word w1 left join sense se1 on w1.wordid = se1.wordid left join synset sy1 on se1.synsetid = sy1.synsetid left join lexlinkref on sy1.synsetid = lexlinkref.synset1id and w1.wordid = lexlinkref.word1id left join word w2 on lexlinkref.word2id = w2.wordid where w1.lemma = '"+ searchedword + "' and lexlinkref.linkid=30",null);
    ArrayList<String> list1 = new ArrayList<String>();
    if (c.getCount() > 0) {
        c.moveToFirst();
        do {            
        list1.add(c.getString(0));
        } while (c.moveToNext());

    }
    myTV.append("\n\nANTONYMS "+list1.toString());
    db.close();


}

class MyHelper extends SQLiteOpenHelper {
    public MyHelper(Context ctx) {
        super(ctx, DB_PATH.getPath(), null, 1);
    }

    public void onConfigure(SQLiteDatabase db) {
        db.execSQL("PRAGMA key = 'secret'");
    }

    public void onCreate(SQLiteDatabase db) {
        db.execSQL("CREATE TABLE t1(x)");
    }

    public void onUpgrade(SQLiteDatabase db, int iOld, int iNew) {
    }
}

/*
 * * If this is a SEE build, check that SQLiteOpenHelper still works.
 */
public void def() throws Exception {
    DB_PATH = new File("/storage/sdcard1/sk2.db");
    String DEFINITION = "select pos, definition, sample FROM word INNER JOIN sense ON word.wordid = sense.wordid INNER JOIN synset ON sense.synsetid = synset.synsetid LEFT JOIN sample ON sample.synsetid =  synset.synsetid  WHERE lemma ='"+ searchedword + "'";
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH, null);
    ArrayList<String> list1 = new ArrayList<String>();
    Cursor mcursor = db.rawQuery(DEFINITION, null);
    mcursor.moveToFirst();
    if (mcursor.getCount() > 0) {
        do {

            list1.add(mcursor.getString(1));
        } while (mcursor.moveToNext());

    }
    myTV.append("\nDEFINATION " + list1.toString());
    db.close();
}

public void run_the_tests(View view) {
    System.loadLibrary("sqliteX");
    myTV.setText("");       
    searchedword = query.getText().toString();
    try {
        report_version();
        def();
        syno();
        anto();

    } catch (Exception e) {
        myTV.append("Exception: " + e.toString() + "\n");
        myTV.append(android.util.Log.getStackTraceString(e) + "\n");
    }
}
}

由于

3 个答案:

答案 0 :(得分:10)

我已经通过添加

解决了这个问题
System.loadLibrary("sqliteX");

创建它们的每个方法

就像这样:

public HashMap<String, ArrayList<String>> word_quiz(String qry) {
    System.loadLibrary("sqliteX");
    ArrayList<String> list1 = new ArrayList<String>();
    ArrayList<String> list2 = new ArrayList<String>();
    SQLiteDatabase db = SQLiteDatabase.openOrCreateDatabase(DB_PATH+ "/sk1.db", null);
    Cursor mcursor = db.rawQuery(qry, null);
    try {
        mcursor.moveToFirst();
        do {
            list1.add(mcursor.getString(0));
            list2.add(mcursor.getString(1));
        } while (mcursor.moveToNext());

    } catch (IndexOutOfBoundsException e) {
        if (MainActivity.logcat_status) {
            Log.e("Error", e + "");
        }
    }
    mcursor.close();
    mcursor = null;
    HashMap<String, ArrayList<String>> final_list = new HashMap<String, ArrayList<String>>();
    final_list.put("list1", list1);
    final_list.put("list2", list2);
    db.close();
    return final_list;

}

现在工作正常

我想我也可以使用构造函数来加载库“sqliteX”

感谢大家考虑我的问题:)

答案 1 :(得分:1)

异常来自com.example.samplesqlitedb.MainActivity$2.onClick()处的代码 com / example / samplesqlitedb / MainActivity.java:56 ,但System.loadLibrary()来自org.sqlite.app.customsqlite.CustomSqlite.run_the_tests()。没有证据表明org.sqlite.app.customsqlite.CustomSqlite活动在发生这种情况时甚至被加载到JVM中。

我建议从libsqliteX.so类的静态构造函数中加载org.sqlite.database.sqlite.SQLiteConnection。也许你可以找到一些更好的地方 - 例如com.example.samplesqlitedb.SearchDataDB类,或应用中扩展 android.app.Application的类(如果有的话)。

答案 2 :(得分:1)

与接受的答案相反,考虑只将调用插入System.loadLibrary函数一次,例如进入DbHelper。

public class MyDbHelper extends SQLiteOpenHelper {

   static {
      System.loadLibrary("sqliteX");
   }
}