I have been trying to implement this functionality for a while, but all my approaches failed.
I would like to have some python code opening a dialog in the android app and wait for the user to click on the ok button (this is the first step I want to complete before I can create more complex YES/NO dialogs).
So far the only behavior I'm able to obtain is a non-blocking dialog, not matter what I try (signals, sockets, shared variables) but it seems like that the dialog is not shown until the python code has ended its execution.
here is my example that uses a global variable to confirm the user has dismissed the dialog:
Python
from java import dynamic_proxy, jboolean, jvoid, Override, static_proxy
from java.lang import Runnable
from com.chaquo.python import Python
from android.app import AlertDialog
from android.content import DialogInterface
import threading
state_done = False
def open_dialog(activity):
def show_dialog():
print('Dialog shown')
builder = AlertDialog.Builder(activity)
builder.setTitle("Title")
builder.setMessage("This is a simple dialog from Python!")
class Listener(dynamic_proxy(DialogInterface.OnClickListener)):
def onClick(self, dialog, which):
print("OK button pressed")
state_done = True
listener = Listener()
builder.setPositiveButton("OK", listener)
dialog = builder.create()
dialog.show()
print('Dialog shown')
class R(dynamic_proxy(Runnable)):
def run(self):
show_dialog()
def dummy():
activity.runOnUiThread(R())
dialog_thread = threading.Thread(target=dummy)
dialog_thread.start()
dialog_thread.join()
while not state_done:
pass
print('done')
Java
if (!Python.isStarted()) {
Python.start(new AndroidPlatform(this));
}
Python py = Python.getInstance();
PyObject pyObject = py.getModule("your_script");
pyObject.callAttr("open_dialog", this);
few notes: with this code, no print is ever executed, it is as if show_dialog
is never called in the first place, no chances that anything is displayed. If I remove the while
loop all the prints are executed in the following order:
I/python.stdout: done
I/python.stdout: show_dialog
I/python.stdout: Dialog shown
*here i press the ok button*
I/python.stdout: OK button pressed
I/python.stdout: dismissed
Is there a way to create a blocking dialog that interface with python directly? indirect solutions are welcomed as well, but even with java callbacks I get the same behavior.
SOLUTION by @mhsmith:
if (!Python.isStarted()) {
Python.start(new AndroidPlatform(this));
}
MainActivity activity = this;
Runnable runnable = new Runnable() {
@Override
public void run() {
// Your code here
Python py = Python.getInstance();
PyObject pyObject = py.getModule("your_script");
pyObject.callAttr("open_dialog", activity);
}
};
Thread thread = new Thread(runnable);
thread.start();
Everything on Android runs on the UI thread unless you explicitly create another thread. So you're probably calling open_dialog
on the UI thread as well, in which case the while
loop will block forever, and the show_dialog
call that was queued on the same thread by runOnUiThread
will never get a chance to run.
Try calling open_dialog
on a background thread instead. You can create it either from Java or from Python. In that case, there will obviously be no need for the dialog_thread
.
You might also want to try BeeWare, which is a higher-level Python app toolkit which runs on Android with the help of Chaquopy, and also on every other major desktop and mobile platform. Here are links to the tutorial, and to the dialog API, which allows you to get the result of a dialog using Python async
syntax.