0

My Target

  • I'm coding an android studio project with some c++ code
  • I want to update UI within c++ code

My Code

The code is as follows:

  • MainActivity.java:
public class MainActivity extends AppCompatActivity {

    // Used to load the 'davdmnn' library on application startup.
    static {
        System.loadLibrary("davdmnn");
    }

    private ActivityMainBinding binding;
    private TextView tv;
    private Button btn;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        // Example of a call to a native method
        tv = binding.sampleText;

        String path = this.getFilesDir() + File.separator;
        stringFromJNI(path);
    }

    /**
     * A native method that is implemented by the 'davdmnn' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI(String path);

    public void sendMessage(int id) {
        tv.setText(id);
    }
}
  • native-lib.cpp
extern "C" JNIEXPORT jstring JNICALL
Java_com_example_davdmnn_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject /* this */, jstring path) {

    for (int i = 0; i < 100; i++){
        // doing sth
        // update tv, like tv.setText(i)
    }

}

My Question

  • I notice my question is related to this one. It uses a handler object to udpate UI, which is good for me.
  • However, to use the solution of the related question, the attribute tv and method sendMessage must be static, which is not what I want.
  • So is there any way that I can pass the object (like this in java) into C++ method Java_com_example_davdmnn_MainActivity_stringFromJNI, or any other solutions?
david
  • 842
  • 2
  • 8
  • 25
  • _"So is there any way that I can pass the object (like this in java) into C++ method"_ You already are: `jobject /* this */` – Michael Oct 09 '22 at 15:09

1 Answers1

1

Thanks to @Michael, jobject /* this */ is actually the java object that calls the C++ function. I modify it into jobject thiz and here is my final code:

  • MainActivity.java
public class MainActivity extends AppCompatActivity {

    // Used to load the 'davdmnn' library on application startup.
    static {
        System.loadLibrary("davdmnn");
    }

    private ActivityMainBinding binding;
    private TextView trainLog;
    private Button btn;
    private Handler handler;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());

        // Example of a call to a native method
        trainLog = binding.sampleText;

        handler = new Handler(){
            public void handleMessage(Message msg){
                trainLog.setText((String)msg.obj);
            }
        };

        String path = this.getFilesDir() + File.separator;
        Runnable mRunnable = new Runnable() {
            @Override
            public void run() {
                stringFromJNI(path);
            }
        };

        btn = binding.startButton;
        btn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                btn.setEnabled(false);
                new Thread(mRunnable).start();
            }
        });

    }

    /**
     * A native method that is implemented by the 'davdmnn' native library,
     * which is packaged with this application.
     */
    public native String stringFromJNI(String path);

    public void sendMessage(int msg) {
        Message msg = Message.obtain();
        msg.obj = Integer.toString(msg);
    
        handler.sendMessage(msg);
    }
}
  • native-lib.cpp
extern "C" JNIEXPORT void JNICALL
Java_com_example_davdmnn_MainActivity_stringFromJNI(
        JNIEnv* env,
        jobject thiz, jstring path) {
    
    // find the java function
    jclass main_activity = (*env).FindClass("com/example/davdmnn/MainActivity");
    jmethodID mid = (*env).GetMethodID(main_activity, "sendMessage", "(I)V");
    for (int i = 0; i < 100; i++){
        // doing sth
        // update tv, like tv.setText(i)
        (*env).CallVoidMethod(thiz, mid, i);
    }

}
david
  • 842
  • 2
  • 8
  • 25
  • Note that it is your responsibility to manage the lifetime of the thread viz the Activity. If the app goes to the background, for example, it is not correct to keep the thread running or keep a reference to the Activity. – Botje Oct 12 '22 at 08:08
  • @Botje thanks, that's a good suggestion. I'll add a notification for the user when the app goes to the background. – david Oct 12 '22 at 10:58