Android Thread in shouldOverrideUrlLoading - java

I had some code in a shouldOverrideUrlLoading, that downloads the data, converting if necessary, and shows in a WebView using loadData or loadUrl. I moved this to a thread (a class implementing Runnable), and now it doesn't lock up the UI while the next page is loading. Unfortunately, sometimes it locks up the whole app, and pausing while debugging shows it seems to be going nowhere (deadlock?)
I'm guessing this is because UI isn't thread-safe, not even webkit loadData/loadUrl? Is there a way to set some sort of onFinish action that runs in UI thread after download/convert has finished? Or would it be enough to store the current thread, and cancel it before running another thread??

adding a synchronized (WebView) { around the thread's code fixes this.

Related

Application freezes when setting TextView text

I have to update a TextView from another class (not a activity) with the result from a method which can be slow to finish its search. While the method don't finish I thought set the TextView text to something like "loading..." and finally, after method result is ok, set the text to that result. Currently I'm doing something like this:
textView.setText("loading...");
Search s = searcher.search();
textView.setText(s.result);
Firstly, this still freezes the application until result is ok, once didn't not used new Threads. I know that to set content to Android widgets we have to do it inside the uiThread, but I don't know how to do it in my case, once I'm not inside a Activity.
In second place, that approach are not showing the "loading..." text. When I call that code the application just freezes and back with the final text.
Then, how to avoid that freeze/breaking until content is ok?
Do not do heavy operation inside MainThread (UI) in Android. For your case take a look to AsyncTask. It give you a method doInBackground where you should make some background stuff (http request, file i/o) then you will get call onPostExecute, that method will called on UI Thread with the results of doInBackground method. Another example.
I think the main thing to understand is that only UI specific tasks should run on the UI thread. If it is not UI related then it should run on another thread ideally as an AsyncTask.
Performing a search, generally speaking, is very performance heavy as you have pointed out. This will block the UI thread from updating the UI which will lead to unresponsive UIs and users may perceive this a crash or a slow app.
So firstly, to run the updating on the UI Thread.
runOnUiThread(() ->{textView.setText("loading...");});
then perform the search on a different thread
then once the search is finished update the UI using the same method as above

i'm so confused about Threads

I read a lot about threads but don't understand yet :( let me explain to you what I have learned about threads. all we are working on such as codes any thing worked on UI thread or Main thread right? After that what happens if we call runOnUiThread? and my other question how do we know it's Time to use a new thread? I mean how do we understand we are working on another thread or replace or code in the new thread?
I know this is an unclear question but I don't understand as well. Please help me Thanks, john.
Let me try to answer. Actually Android has Main Thread (also called as UI Thread) and other thread.
Main Thread is basically for showing UI and other thread is for processing other big processes such as connecting to the server, etc.
runOnUiThread is called when you want to move from other thread to main thread. It is needed since only main thread can show/display result on UI. So when you have done some process on other thread, and you want to display the result on the apps, you need to show it on main thread by calling runOnUiThread.
We working on other thread only if it is a big or lengthy process like taking data from the server, load data, etc. And we move from other thread to main thread whenever we want to show some UI result.
Easiest way is to use AsyncTask<> class. You'll need to override three functions.
doInBackGround(...) : The codes that gets executed in background thread.
onPreExecute(..) : code that gets executed before background thread
completes executing like displaying progress bars, etc.
onPostExecute(...): Code that gets executed after background thread
has completed running. Perform task like updating UI in here
One general rule of thumb is: Don't use multithreading if you don't need to. Multithreading is always error-prone, and in many situations there's no benefit. Basically, you start a new thread whenever you execute a lengthy operation (i.e. some extensive computation like image processing) that would block the main thread for some time, so the application would become unresponsive.

Android Webview loadUrl does not work when coming from a worker thread

I am developing an app that contains a web view. A certain times during the app it does a call to Webview loadUrl.
Sometimes the call will come directly from an event on the UI thread and other times it comes from an event on a background worker thread. When it originates from the background thread I do a call to runOnUIThead() to ensure the actual call to loadURL happens on the UI thread.
What I am experiencing is that loadUrl() works fine when originating from the UI thread, however it fails to work when it comes from a worker thread (even though the actual call to loadUrl happens via a runnable I pass into runOnUIThread()).
Having set a break point I can see that in both instances loadUrl() is being called on the UI thread. Yet it works in one case but not the other.
I am currently sifting through the Android Webview source code to see if I can track down why sometimes it works and sometimes it doesn’t. If anyone can shed any light on the matter it would be greatly appreciated.
--- UPDATE ---
I have tried a few suggestions from this post here: WebView loadUrl works only once
Mainly doing the following before calling loadUrl:
webView.clearCache(true);
webView.loadUrl("Url");
And:
webView.clearCache(true);
webView.clearView();
webView.reload();
webView.loadUrl("about:blank");
webView.loadUrl("Url");
Unfortunately neither of them work.
In general, its not safe to create view outside of main thread.
In your particular case, this is not allowed, because WebView creates Handler() in its constructor for communication with UI thread. But since Handler's default constructor attaches itself to current thread, and current thread does not have Looper running, you're getting this exception.
You might think that creating a looper thread (that must be alive at least as long as WebView) might help you, but this actually a risky way to go. And I wouldn't recommend it.
You should stick with creating WebViews in main thread. All controls are usually optimized for fast construction, as they are almost always created in UI thread.
or You can call webview like this
runOnUiThread(new Runnable() {
#Override
public void run() {
// your webview method
}
});

When off the main thread, how can I get some code to run on the main thread as quickly as possible?

I have an user interface that is partly web based (WebView). It is connected to the Android UI through a Javascript Interface. When you tap on an element in the WebView, javascript calls up to Android and Android receives the call on the javascript/web thread. Not the UI (main) thread.
It arrives in Android in 1 or less milliseconds. No problem there. However, because I want to now change the UI, I have to switch over to the UI thread. (Android throws an exception if you modify the UI from off the main thread). I am currently using a Handler on the UI Thread and calling post().
This code (a Runnable) is then called anywhere between 120 and 300 ms later. This is a very noticeable lag for the UI to change from the user's touch.
Is there any way to get some code to run on the UI thread faster? Here is some example code:
An interface class:
public class JSInterface {
public void test() {
// Arrives here in 1ms after calling AndroidInterface.test(). Arrives n the web thread.
runOnUiThread(new Runnable() {
#Override
public void run() {
// Arrives here 100ms to 300ms after calling AndroidInterface.test(). Arrives on the main (UI) thread.
}
});
}
}
Added to a webview like this:
webview.addJavascriptInterface(new JSInterface(), "AndroidInterface");
Called in javascript like this:
AndroidInterface.test();
Thanks!
Is there any way to get some code to run on the UI thread faster?
runOnUiThread() and kin put a message on a message queue that the main application thread works off of. Much of the time, the main application thread's job is to pull a message off the queue and process it. However, the main application thread is responsible for calling most of your callbacks as well.
If you are seeing "120 and 300 ms" delays, that means one of two not-mutually-exclusive things:
The queue has quite the backlog
The main application thread is busy executing some other code
The relationship between WebView, the queue, and the main application thread is rather mysterious, compared to normal widgets, because WebView isn't a classic widget rendered in Java code. Hence, I have no idea if there is something that is occurring in your Web content that might explain this, or if this is fairly normal for WebView. You might try an experiment with simpler Web content and see whether you get similar delays, or if the delays are somehow more tied to the specific Web content that you are rendering.
Push come to shove, use Handler and postAtFrontOfQueue(). As the JavaDocs for that method note, though, this is dangerous.

Android - Thread.sleep and Handler.postDelayed() freezes animated UI elements

In my activity, my app downloads a list of something from a website via an Http Connection. Before this list of things is displayed on the screen, I have a Loading... TextView with a little spinning ProgressBar to indicate that the data is currnetly being downloaded.
I noticed, that if I do any type of Thread.sleep() during the process of fetching the data from the web, it freezes the spinning ProgressBar.
Even if I put the method in it's own Handler Runnable so that it's on it's own thread, the animation freezing still occurs.
Is there anything I can do about this?
Yes, use AsyncTask.
A Handler is usually attached to the UI thread. Posting Runnables to it doesn't change the fact that they will run on the UI thread.
Any application should do long running tasks on a seperate thread to the UI thread as any blocking calls will not allow the UI to update.
As the other poster said, using Runnables alone do not mean the code will be executed on a seperate thread. In this case the run() method will execute on whatever thread your Handler object was created on. Either subclass Thread or pass your runnabe to new thread object with public Thread (Runnable runnable).
Using AsyncTasks, Loaders or Threads will help.
Also read Designing for Responsiveness and Multithreading For Performance. Following the above approaches will help you avoid ANRs
The reason for such a behaviour is that:
When you do thread.sleep() inside a runnable, it is the UI thread which executes that runnable rather than the respective other thread which you created. Basically what happens is that when you post any runnable through the handler of the UI thread, UI thread will poll from its queue and execute the runnable; in this case the runnable will do sleep.
Hence no change in progress bar

Categories