Webview.loadurl inside #JavascriptInterface will crashes the app - android

I have a webview, which is running on main thread and i am calling webview.loadurl("https://www.google.com")
its loading fine.
webview has following setting, so javascript function call some of native function.
webView.addJavascriptInterface(this, name)
and this class has one method with #JavascriptInterface annotation
#JavascriptInterface
fun getTestData(){
**webview.loadURL("https://www.facebook.com")**
}
the bold one webview.loadURL("https://www.facebook.com") is getting crashed with following error:
java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread. (Expected Looper Looper (main, tid 2) {95d9516} called on Looper (JavaBridge, tid 1144) {e018910}, FYI main Looper is Looper (main, tid 2) {95d9516})
I have checked for threads and webview is running on main thread, and while the control comes under the method getTestData(), the thread is javabridge.
Any help would be appreciated

run your code in UI thread, JS interfaces are called in some other (looks like)
#JavascriptInterface
fun getTestData(){
Handler(Looper.getMainLooper()).post {
webview.loadURL("https://www.facebook.com")
}
}
from stacktrace:
All WebView methods must be called on the same thread
and you are creating WebView instance always in UI thread (as this is View, should be drawn...)
also if you are in Activity then you can use runOnUiThread{}

You need to call Android Web view related things on UI thread.
webView.post {
webView.loadUrl("https://www.facebook.com")
}

Related

Creating PDF in separate thread STILL making main thread unresponsive

I am not sure what I am doing wrong here but my main thread is blocked (as per Android studio's message : I/Choreographer: Skipped 1009 frames! The application may be doing too much work on its main thread.) although I am using a seperate thread to create my PDF using itext.
+
My spinner class, my toast do not show as well, both are written in main thread (perhaps because of main thread being unresponsive as per the message). Once the PDF is created, the dialog shows up as normal and everything starts working as expected.
val bmap = BitmapFactory.decodeResource(this#SiteItemsActivity.resources,R.drawable.camera_item_center)
val threadPDF = Thread(object : Runnable {
override fun run() {
CreatePDF(file, site, bmap).makePDF()
}
})
threadPDF.start()
spinner.setVisibility(View.VISIBLE)
Toast.makeText(this#SiteItemsActivity,"Please wait....",Toast.LENGTH_SHORT).show()
while (threadPDF.isAlive){
//Thread.sleep(1)
}
spinner.setVisibility(View.GONE);
showDialog()
although I am using a seperate thread to create my PDF using itext
But then you are tying up the main application thread with an continuous loop (while (threadPDF.isAlive)).
Delete that while loop. Use other solutions for updating your UI when the work is done. For example, you could:
replace your thread with an AsyncTask and update your UI in onPostExecute()
have your thread post() a Runnable (using your Spinner) to have that Runnable be run on the main application thread after your thread's work is done
replace your thread with an RxJava Observable, where you schedule its work a background thread (e.g., Schedulers.io()) and observe it on the main application thread (AndroidSchedulers.mainThread())
wrap your thread in a LiveData object and have your UI code observe that LiveData for the completion of the work
and so on

How to address this issue "method must be called from UI thread"

I am trying to open a URL using WebView (positioned inside a Fragment) from AsyncTask.
Butterknife is being used to bind the view (WebView in this). The following code related to WebView is written inside doInBackground() of AsyncTask
mWebView.getSettings().setJavaScriptEnabled(false);
mWebView.setScrollBarStyle(View.SCROLLBARS_INSIDE_OVERLAY);
However, on writing the code related to WebView, the IDE warns me with "Method getSettings() must be called from the UI thread, currently inferred thread is worker"
What does this mean? I am sorry, but can someone explain what's happening. Should I use something like runOnUiThread()?
You have to move mWebView.getSettings().setJavaScriptEnabled(false); inside your OnCreate() in runOnUiThread() method.
Either write mWebView.getSettings().setJavaScriptEnabled(false); in runOnUiThread() or move it to onPostExecute()
You can't update the mWebView.getSettings().setJavaScriptEnabled(false); from a background Thread. You will need to do this in either onPostExecute() or OnCreate Method

Android - myLooper() vs getMainLooper()

Just clarifying but in an Android activity on MAIN Thread if I call Looper.myLooper() vs Looper.getMainLooper() the return the same reference, right? they are the same thing? I know I would never have to call these usually as Android takes care of this but I'd like to know how they differ when being called from the main thread?
if from the main thread I call
Looper.myLooper().quit();
// or
Looper.getMainLooper().quit();
They both give the same runtime exception so I'm assuming they are the same reference:
Caused by: java.lang.RuntimeException: Main thread not allowed to quit.
can anyone confirm?
You have it described in the docs:
getMainLooper()
Returns the application's main looper, which lives in the main thread of the application.
myLooper()
Return the Looper object associated with the current thread. Returns null if the calling thread is not associated with a Looper.
As for whether getMainLooper() is of any use, I can assure you it really is. If you do some code on a background thread and want to execute code on the UI thread, e.g. update UI, use the following code:
new Handler(Looper.getMainLooper()).post(new Runnable() {
// execute code that must be run on the UI thread
});
Of course, there are other ways of achieving that.
Another use is if you want to check if the currently executed code is running on the UI thread, e.g. you want to throw/assert:
boolean isUiThread = Looper.getMainLooper().getThread() == Thread.currentThread();
or
boolean isUiThread = Looper.getMainLooper().isCurrentThread();
Looper.getMainLooper() is convenience API to get looper which is attached to the main thread of the activity.It is usefull when you want to excute some code on main thread from a background thread.
It is usually used as follows:
new Handler(Looper.getMainLooper()).post(task);
Looper.myLooper() is api to get looper attached to current thread
If you call these two methods in the main thread, they are the same object! You can find answers in the source code of ActivityThread.java, Looper.java and ThreadLocal.java.

Webview JavascriptInterface loadUrl Wrong Thread

I have a problem with the webview and the javascriptinterface. The webview is inside a fragment, which can removed from the viewpager. Sometimes i call the method loadUrl and i am on the wrong thread and the app crash. That crash is ok if iam on a background thread and i call loadUrl from the background thread without a post to the UI-Thread. But i have implemented the following and with this i think the crash shouldnt happen:
mWebView.post(new Runnable() {
#Override
public void run() {
mWebView.loadUrl("javascript:" + _callback + "()");
}
});
Nevertheless i get sometimes the following crash:
java.lang.RuntimeException: java.lang.Throwable: A WebView method was called on thread 'JavaBridge'. All WebView methods must be called on the same thread. (Expected Looper Looper (main, tid 1) {189b08de} called on Looper (JavaBridge, tid 160593) {2c1874b2}, FYI main Looper is Looper (main, tid 1) {189b08de})
I cant found out when this happens and this is not reproducable.
Can this happen when the fragment is removed from the viewpager and i call the loadUrl method?
Anyone a idea when this happens?

Why should some methods be invoked only from the main application thread?

I read about this class:
Do not instantiate this class directly, instead, call
createSpeechRecognizer(Context). This class's methods must be invoked
only from the main application thread.
I suppose that the main application thread is the main Activity of an Android application...
Why should this class's methods be invoked only from the main application thread?
The main application thread is also known as the UI thread.
This is done to ensure thread safety. (No two processes can modify the same value at the same time).
Please see: Why can only the UI thread in Android update the UI?

Categories

Resources