3

I am writing an Android App where I need to have two persistent values that have to be read by the App. The App needs to maintain a counter which has to be stored 'somehwhere' and retrieved each time the Activity is launched. The counter is then updated and then stored before the Activity is shut down.

The important point is that I want the storing and retrieval of the counter to be done by the JNI part of my code. It should be practically invisible to the Java code.. Can this counter(memory) be accessed using JNI? If so, can you point me to which API I have to look? I know one can use the SQLiteDatabase on the Java side. Please advise!

user900785
  • 423
  • 3
  • 14
  • 32

2 Answers2

4

It's perfectly possible, but not without some Java code.

EDIT : the following is offered as an alternative to a database. Being able to read and write persistent data to/from files from native code would be a lot more flexible than a database...

Assuming you want to store and retrieve some data from a file (binary or plain text) residing on the filesystem these would be the steps to take:

  1. JAVA : get the storage location for your app and check if it's available for reading and writing

  2. JAVA : if the above is positive, pass it to the native layer through JNI

  3. NATIVE : use the storage params to read/write your file

Ok, so far the abstract; lets get to the code:

1A) retreiving and checking storage:

private boolean checkExternalStorageState(){
        String state = Environment.getExternalStorageState();

        if (Environment.MEDIA_MOUNTED.equals(state)) {
            // We can read and write the media
            android.util.Log.i("YourActivity", "External storage is available for read/write...", null);
            return true;
        } else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
            // We can only read the media : NOT ok
            android.util.Log.e("YourActivity", "External storage is read only...", null);
            return false;
        } else {
            // Something else is wrong. It may be one of many other states, but all we need
            //  to know is we can neither read nor write
            android.util.Log.e("YourActivity", "External storage is not mounted or read only...", null);
            return false;
        }
    }

Get the storage location :

private get storageLocation(){
    File externalAppDir = getExternalFilesDir(null);
    String storagePath = externalAppDir.getAbsolutePath()
}

1B) you also might want to check if a file exists (you can also do this in the native part)

private boolean fileExists(String file) {

        String filePath = storagePath + "/" + file;

        // see if our file exists
        File dataFile = new File(filePath);
        if(dataFile.exists() && dataFile.isFile())
        {
            // file exists
            return true;
        }
        else
        {
            // file does not exist
            return false;
        }
    }

2) Pass it to the native layer:

JAVA part:

// Wrapper for native library
public class YourNativeLib {


     static {
         // load required libs here
         System.loadLibrary("yournativelib");
     }

     public static native long initGlobalStorage(String storagePath);
     ...enter more functions here

}

NATIVE part:

JNIEXPORT jlong JNICALL Java_com_whatever_YourNativeLib_initGlobalStorage(JNIEnv *env, jobject obj, jstring storagePath)
{
    jlong data = 0;

    // convert strings
    const char *myStoragePath = env->GetStringUTFChars(storagepath, 0);
    // and now you can use "myStoragePath" to read/write files in c/c++

    //release strings
    env->ReleaseStringUTFChars(storagePath, myStoragePath);

    return data;
}

How to read/write binary or text files in c/c++ is well documented, I'll leave that up to you.

Erik
  • 804
  • 1
  • 8
  • 18
  • Thanks for the answer. But what I don't get is, if I know the path to the file, why doI need to pass this from the Java side? The aim o my code is to somehow "hide" to the java layer all about the counter.. – user900785 Jun 02 '13 at 16:50
  • The only thing this code is for is to retrieve and pass the default storage location in the filesystem... it doesn't know about any counter. How you read, write or process your counter can be done in entirely in c/c++ and would be invisible to java. But afaik you need java to give you that location where you can write to and read from. – Erik Jun 03 '13 at 12:16
1

You can use SQLite from NDK side by including SQLite amalgamation ( http://www.sqlite.org/download.html ) in your project.

See SQLite with Android NDK

Community
  • 1
  • 1
Guillaume
  • 10,463
  • 1
  • 33
  • 47