5

I wish to print the output from printf statements in my native code(in C) on to android screen. As I have many outputs that I wish to see on android screen, I want something more than the return statements at the end of a JNI functions which print a single text per function. How to go about it?

EDIT:

For example in my C code, if I wish to print something in the middle of a function like "Hello World" what should I do? Right now, I am able to print "only from return!" on the android screen using setText methods.

jstring Java_com_example_encryptString( JNIEnv* env, jobject thiz) 
{
   printf("Hello World");
   return (*env)->NewStringUTF(env, "only from return!");
}

I know of a method where I call this method from the Java class and use TextViews to print it on android screen. But, that can take and print only the value returned by the function and nothing else. Can't I print any other value which is not returned by the function?

Thanks.

Note: I am not looking for android logs in logcat.

re3el
  • 735
  • 2
  • 12
  • 28
  • Put one or more `TextView`s in your layout and call their `setText` methods. – Michael Nov 10 '15 at 06:15
  • @Michael: Isn't that printing the return values from the native function? If so, wouldn't it be too exhausting to write a function every time I wish to print. I am a novice here and sorry for my banality. – re3el Nov 10 '15 at 07:16
  • _"Isn't that printing the return values from the native function?"_. Huh? You can put as many log prints as you want in a function (and as many `setText` calls as you want). – Michael Nov 10 '15 at 07:19
  • @Michael am not quite sure of what you mean. Could you kindly mention a sample code of what you are speaking about? – re3el Nov 10 '15 at 07:27
  • @Michael: If I wasn't clear, I wish to print from native code in C, not java. – re3el Nov 10 '15 at 07:38
  • I think you should post that code of yours that only can print _"the returns statements"_. I really don't understand what you mean by that. You can put as many prints as you want in a function - doesn't matter if it's C code or Java code. – Michael Nov 10 '15 at 07:40
  • @Michael: kindly check the edited question. – re3el Nov 10 '15 at 07:50
  • Why would a function named `encryptString` be responsible for displaying anything on the screen? Anyway, if you do want to display some text on the screen, you can do what I suggested in my first comment and use some `TextView`s. You can access Android Java classes from your C code just as you would with any other Java class. If you don't know how to access Java classes through JNI then you should do some reading on the subject first. – Michael Nov 10 '15 at 10:05
  • That was my whole point. I knew of a method in which I call native functions in C from java and print them later using `TextViews`. But, in this method I cannot print every printf statement as needed from my C code. I can only print values from the return statement. I was asking for a way to solve that problem – re3el Nov 10 '15 at 10:08
  • _"I cannot print every printf statement"_ What's stopping you from replacing all the `printf` calls with calls to some `TextView`'s `setText` method? – Michael Nov 10 '15 at 10:11
  • okay. I didn't know that I could use setText inside native C programs. I will look into this – re3el Nov 10 '15 at 10:14
  • @Michael: Could you explain with a snippet on what you meant! I have been trying a lot but in vain – re3el Nov 10 '15 at 14:12

1 Answers1

4

If I understood your question correctly, you meant to set text in a TextView from c code, right?

If so, you can do that. You need to pass the TextView as a param to your native method. Then in your native code call find its setText method and call it.

You can read more on this thread on SO or this page.

You will change your native method to something like this :

jstring Java_com_example_encryptString( JNIEnv* env, jobject thiz, jobject jtextViewObject, ...)
{
    //getting set text method
    jclass clazz = (*env)->FindClass(env, "android/widget/TextView");
    jmethodID setText = (*env)->GetMethodID(env, clazz, "setText", "(Ljava/lang/CharSequence;)V");

    ... do stuff ...

    //set text to text view
    jstring jstr = (*env)->NewStringUTF(env, "This comes from jni.");
    (*env)->CallVoidMethod(env, jtextViewObject, setText, jstr);

    ... do stuff ...

    return (*env)->NewStringUTF(env, "only from return!");
}

You will also need to change the signature of the native method in java code to add the TextView in the params.

Community
  • 1
  • 1
sonic
  • 1,894
  • 1
  • 18
  • 22
  • yes, this might be the solution I was looking forward to. I am getting `expected expression before 'jmethodID'`error while building the project. how to fix it? – re3el Nov 10 '15 at 10:40
  • After commenting the above line, I am getting `Illegal class name /android/widget/TextView ` error and many others. – re3el Nov 10 '15 at 11:09
  • Ok. Maybe try `jclass clazz = (*env)->GetObjectClass(env, jtextViewObject);` instead of `jclass clazz = (*env)->FindClass(env, "/android/widget/TextView");`. – sonic Nov 10 '15 at 12:09
  • after the above edit I get `JNI NewStringUTF called with pending exception java.lang.NoSuchMethodError: no non-static method "Landroid/widget/TextView;.setText(V)Ljava/lang/String;"` errors – re3el Nov 10 '15 at 12:25
  • I have made a typo. It should be `jmethodID setText = (*env)->GetMethodID(env, clazz, "setText", "(Ljava/lang/String;)V");` – sonic Nov 10 '15 at 12:51
  • problem persists `JNI NewStringUTF called with pending exception java.lang.NoSuchMethodError: no non-static method "Landroid/widget/TextView;.setText(Ljava/lang/String;)V"` – re3el Nov 10 '15 at 12:55
  • I am confuse. The method `NewStringUTF` has nothing to do with the `jmethodID`. You getting this error, at compilation or at runtime ? – sonic Nov 10 '15 at 13:12
  • I am getting this at run time – re3el Nov 10 '15 at 14:04
  • I forget another typo, it should be `(*env)->CallVoidMethod(env, jtextViewObject, setText, jstr);` with `setText` instead of `jmethodID`. Let me know if it still doesn'y work. I will try it at home tonight. – sonic Nov 10 '15 at 14:20
  • From the edited code, I am getting illegal class name error again at runtime. Thanks a lot for looking into this. I really mean it :) – re3el Nov 10 '15 at 14:31
  • 2
    There's a small issue in the code.. it should be `(Ljava/lang/CharSequence;)V` instead of `(Ljava/lang/String;)V` – chaitan94 Nov 11 '15 at 05:35
  • 2
    Note that, the way it is written now, the native method `encryptString()` must be called from the main (UI) thread. – Alex Cohn Nov 11 '15 at 07:39