Webview JavascriptInterface loadUrl Wrong Thread - android

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?

Related

Webview.loadurl inside #JavascriptInterface will crashes the app

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")
}

branch.io loadRewards - Can't create handler inside thread that has not called Looper.prepare()

I am using branch.io for referrals. When I make a call to load the rewards using loadRewards(), I get the following exception:
Fatal Exception: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
at android.os.Handler.(Handler.java:204)
at android.os.Handler.(Handler.java:118)
at io.branch.referral.InstallListener.captureInstallReferrer(InstallListener.java:56)
at io.branch.referral.Branch.registerAppInit(Branch.java:2340)
at io.branch.referral.Branch.initializeSession(Branch.java:2298)
at io.branch.referral.Branch.initUserSessionInternal(Branch.java:1286)
at io.branch.referral.Branch.handleNewRequest(Branch.java:2450)
at io.branch.referral.Branch.loadRewards(Branch.java:1699)
at com.musicmuni.riyaz.data.AppDataRepositoryImpl.getReferralCredits(AppDataRepositoryImpl.java:2926)
.......
Looking the error message, it seems that the call required to be triggered from a UI thread. But since this is a network call, this seems unusual. Is there anything that I am missing?
this crash can only happen when you call initSession from a non-UI thread. You are creating the handler inside the thread that has not called Looper.prepare(), so can you please make sure the initSession is happening on the main thread?

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.

How to run two fragments each with their own AsyncTasks

I have a layout with 2 tabs in it which are implemented via fragments i.e. each tab has its own fragment. They is a SwipeRefreshLayout in each of the layouts associated with the fragments.
Also there are two async tasks which make an http call to a script that returns JSON data.I implemented the first async task and it worked fine but however when I tried executing the second one the app keeps crashing. Log cat is not of much help but these were the most important lines I saw:
java.lang.RuntimeException: An error occured while executing doInBackground()
Caused by: java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
These errors occured when an http request was created. Any idea how I can get around this?
In a different thread from the UI thread you must create a Handle and send a runnable for the UI thread . follows the code
Handler handler = new Handler (Looper.getMainLooper());
handler.post (new Runnable () {
#Override
public void run () {
// ... Update view
}
});

What is the difference between widget post() vs. handler post()?

I have a WebView which I initialize with loadUrl in AsyncTask.doInBackground. I initialize it like below :
webView.post(new Runnable() {
#Override
public void run() {
webView.loadUrl(authURL);
}
});
AsyncTask is executed as last in Activity.onCreate(), the problem is that most of the time webpage does not get loaded, I see white screen. If I replace webView with handler then all is ok. What am I missing here?
Why are you doing this in doInBackground() if it needs to run on the UI thread anyway?
The difference between Hander.post() and View.post() is that Handler will run your code
on the thread the Handler instance was created on (which is not necessarily the UI thread), while View will always run it on the UI thread (because views are bound to it).

Categories

Resources