Open cldtech opened 4 days ago
set_wakeup_fd only works in main thread of the main interpreter
The first Google result for this error message indicates that it was fixed in Python 3.9. To change the Python version of your app, follow these instructions.
Alternatively, if you call Python.start
on a different thread, then Python will consider that to be the main thread. It doesn't need to be the same as the main thread in Java.
Of course i googled this, but it still doesn't work. I was already on Python 3.12, i tried 3.9 just to make sure but it does the same errors. But Putting Python.start in the thread did it, i just had to remove android:name="com.chaquo.python.android.PyApplication"
from the manifest.
Thanks for this project by the way, it's much needed!
I spoke too fast, it worked with an empty Quart app but as soon as i add a call to Kotlin from Python i get Error starting Python server: Can't create handler inside thread Thread[Thread-4,5,main] that has not called Looper.prepare()
from MainActivity. So i added a call to Looper but that gives me Error starting Python server: Method addObserver must be called on the main thread
even though the call to run the Quart app is in the thread where the Python interpreter is started.
Kotlin:
package com.example.chatterbot
import android.annotation.SuppressLint
import android.net.http.SslError
import android.os.Bundle
import android.os.Looper
import android.util.Log
import android.webkit.SslErrorHandler
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.appcompat.app.AppCompatActivity
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.chaquo.python.Python
import com.chaquo.python.android.AndroidPlatform
class MainActivity : AppCompatActivity() {
private val tag: String = "MainActivity" // Define a tag for your logs
private var serverPort: Int? = null
private lateinit var webView: WebView
private lateinit var swipeRefreshLayout: SwipeRefreshLayout
@SuppressLint("SetJavaScriptEnabled")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Run the Python server in a background thread
Thread {
Looper.prepare()
Log.i(tag, "Starting server")
Log.i(tag, "IS STARTED")
Log.i(tag, Python.isStarted().toString())
if (! Python.isStarted()) {
Python.start(AndroidPlatform(this))
}
try {
val py = Python.getInstance()
py.getModule("app").callAttr("run")
} catch (e: Exception) {
Log.e(tag, "Error starting Python server: ${e.message}")
}
Looper.loop()
}.start()
// Set webview
Log.i(tag, "Starting webview")
webView = findViewById(R.id.webview)
webView.webViewClient = object : WebViewClient() {
override fun onReceivedSslError(
view: WebView?,
handler: SslErrorHandler?,
error: SslError?
) {
// Ignore SSL certificate errors (not recommended for production)
handler?.proceed()
}
}
webView.settings.javaScriptEnabled = true
webView.loadUrl("file:///android_asset/iframe/iframe.html")
swipeRefreshLayout = findViewById(R.id.swipe_refresh_layout)
swipeRefreshLayout.setOnRefreshListener {
webView.reload() // Reload the current page
swipeRefreshLayout.isRefreshing = false // Stop the refreshing animation
}
}
fun closeLoader() {
Log.i(tag, "Close loader")
webView.evaluateJavascript("closeLoader();", null)
}
}
Python:
from hypercorn.asyncio import serve
from hypercorn.config import Config
from quart import Quart, render_template
from com.example.chatterbot import MainActivity
activity = MainActivity() # <-- **The problem comes when i add this**
app = Quart(__name__)
config = Config()
config.bind = [f"0.0.0.0:8000"]
config.debug = True
@app.route('/')
async def index():
return await render_template('index.html')
@app.after_serving
async def after_startup():
# This code will run after the server is fully loaded and ready to receive requests
print("Server ready")
activity.closeLoader()
def run():
app.run(host="0.0.0.0", port=8000, debug=True)
If you want help with an error message, you must always post the full stack trace.
activity = MainActivity() # <-- **The problem comes when i add this**
You never create an activity explicitly in Android. The system creates it, and calls methods on it. If you want to access it from Python code, just pass this
as an argument when you call run
, and store it somewhere on the Python side.
Hi, this is not exactly a bug i assume but nothing in the rather short documentation or from online searches could help me. I am trying to build an android app that runs a Quart app in background with Chaquopy and a web view to display it full screen. The problem is i can't find a way to run Chaquopy without blocking the main thread which is kind of pointless, no matter what i try there is an error!
Here's why i can't figure it out:
So is it simply impossible to run a python web server and a webview in the same android app?
Running Chaquopy in the activity like such blocks the main thread and the UI (webview) stops working:
I tried running Chaquopy in an android thread as such:
Which give me this error from the activity:
I tried running the server in a Python thread like this:
Which give me this error in logcat through python.stderr:
I tried running Chaquopy in a coroutine:
Which does start the server but still blocks the main android thread and cause this error:
I don't know what to try next and can't find much online, is running a webserver in Chaquopy whthout blocking the UI impossible?