Android bug: WebViewCore fails with Assertion error - android

Unfortunately I cannot reliably reproduce this error but infrequently I get it and occasionally it gets reported in the live crash logs also. Here's a stacktrace reported by user with Droid 2.2.2 FRG83G
junit.framework.AssertionFailedError
at junit.framework.Assert.fail(Assert.java:47)
at junit.framework.Assert.assertTrue(Assert.java:20)
at junit.framework.Assert.assertNull(Assert.java:233)
at junit.framework.Assert.assertNull(Assert.java:226)
at android.webkit.WebViewCore$WebCoreThread.run(WebViewCore.java:594)
at java.lang.Thread.run(Thread.java:1096)
This seems to be due to this line in WebViewCore.java
Assert.assertNull(sWebCoreHandler);
Somehow sWebCoreHandler which is private static instance of android.os.Handler is not (Thanks #Idolon for the correction) already initialized but I have no clue how to work around or prevent this issue.
This occurs often enough for me to worry. What is also interesting is seemingly happens when the app is loading Activity that doesn't even have WebView though one of the activities does have it.
P.S. This was filed as bug #16258

Looking at the incriminating source code...
public WebViewCore(Context context, WebView w, CallbackProxy proxy,
Map<String, Object> javascriptInterfaces) {
//....
// We need to wait for the initial thread creation before sending
// a message to the WebCore thread.
// XXX: This is the only time the UI thread will wait for the WebCore
// thread!
synchronized (WebViewCore.class) {
if (sWebCoreHandler == null) {
// Create a global thread and start it.
Thread t = new Thread(new WebCoreThread());
//...
}
}
//...
private static Handler sWebCoreHandler;
// Class for providing Handler creation inside the WebCore thread.
private static class WebCoreThread implements Runnable {
public void run() {
Looper.prepare();
Assert.assertNull(sWebCoreHandler); // this assertion fails
synchronized (WebViewCore.class) {
sWebCoreHandler = new Handler() {
//...
This is executed in the constructor of any WebView and the assertion error comes from the WebCoreThread constructor, which is only called when the sWebCoreHandler is null, so this assertion should never fail... in theory. Except it's ran outside of the synchronized clause and inside a new Thread that is created and started inside a synchronized clause, supposedly only once.
It seems your error is tied to concurrent creation of webviews. If your application has only one activity with one webview, make sure that this activity is not called more often than necessary (=one at a time), that the WebView is created in the onCreate method rather than the activity constructor, that the startActivity is called in the main thread, and you should be good.

Related

android while loop alternative

This is my first Android application and I am finding troubles with while loop, I am trying to use a while loop on my Android application but the application freezes.
What I'm trying to do is track the user location (using onlocationChanged) and keep querying on the location until the query returns a result. It's a GIS application so I am going to describe the application behavior:
the application keeps tracking the user position using a listener "onLocationChangedListener" and store it in a variable "myPosition". I am using a boolean"noResults=true". I will use a method "query(myPosition)" in the while loop, this method has a callback that when a result is found, and changes a boolean "noResults" to false. the loop will keep on until "noResults" is false (that means query's callback changed the boolean's value)
, here's what I did:
while(noResults)
{
//myPosition keeps changing
query(myPosition);
//query has a callback that when a result is found it changes noResults to false
}
I resolved the problem using a "Handler" that query the Feature Layer every 5 seconds, this stops the main thread from generating application not responding error:
Handler m_handler=new Handler();
Runnable m_runnable;
m_runnable = new Runnable(){
public void run() {
//query code here
m_handler.postDelayed(m_runnable, 5000);
}
};
m_handler.postDelayed(m_runnable, 0);
running while loop codes on the main thread freezes the UI, and makes all other processes pause making your app unresponsive use
Threads..
also note that the while loop you are running is running on a default Thread termed as the ui thread so in short run while loops on separate threads..
eg..
new Thread(new Runnable() {
#Override
public void run() {
// Your hard while loop here
//get whatever you want and update your ui with ui communication methods.
}
).start();
for ui communicating methods
View.post(new Runnable() {
#Override
public void run() {
// TODO Auto-generated method stub
Toast.makeText(getActivity(), "updated ui", Toast.LENGTH_LONG).show();
}
});
the view could be any views you are updating..
also like #TehCoder said you could use asynctask but asynctask is not meant for long workaflow work there are 3 of them but i can't recall the last one
Maybe you should use an AsyncTask? I'm not quite sure what your problem is tho.
Loop is not a problem in android (or any language).
There are two scenario might be reason for your freezing,
If you run network call in api, android throw error and crashes. You have to do network related calls in Aysnc Task ot threading
Use try throw catch and exception cases to avoid app crashing and better coding skill.

How to get user feedback (e.g. from AlertDialog) inside AsyncTask/Background-Thread?

an Android 4+ app should perform a long running operation. This could be copying a million files from A to B for example. To not block the UI this operation runs in the background using an AsyncTask.
Assume that the operation needs some user feedback in the middle of the process to continue its work, e.g. "File XY already exists. Override, Irgnore or Rename?"
What is the best way to get this feedback from the user? Since the operation is running in a background thread one could not just present an AlertDialog (or something similar) since UI interaction is only possible in the main thread...
So for I came across these solution:
Ask for feeback before background threads starts, e.g. ask how to handle conflicts before starting to copy/move the files in the
background.
Do not handle conflicts but note them to ask the user
how to handle them after the operation is complete in a new
operation.
End the background operation on the first conflict, ask the user for feedback and continue a new background operation
I do not like any of these solutions. In the first case the user is asked for feedback even if there will be no conflict at all. The second solutions is not possible if the steps have to be processed in a specific order. The third solution would result in code that is very difficult to read/understand/maintain.
A good solution would be:
Stop the background thread
Marshal to the UI thread and get feedback from the user
Resume background thread and use feedback to continue the operation
Using GCD in Objectiv-C/iOS or async/await in C# this is not a big problem. But how can this be done in Android using AsyncTask?
Meanwhile I thought, that I found an answer here: Simply run myActivity.runOnUiThread(...) within doInBackground(...) and wait for it. Sounds good, but it does not work. The AsyncTask/background thread does NOT wait for the Runnable to finish:
private void copyFiles() {
CopyTask copyTask = new CopyTask (this);
copyTask.execute();
}
private class CopyTask extends CustomAsyncTask<Void, Void, Void> {
private doCopy;
#Override
protected Boolean doInBackground(Void... params) {
// Custom code, e.g. copy files from A to B and check for conflict
for (File file : allFiles) {
doCopy = true;
if (isConflict(file)) {
// Stop current thread and ask for user feedback on UI Thread
Runnable uiRunnable = new Runnable() {
public void run() {
// Pos 1. --> Execute custom code, e.g. use AlertDialog to ask user if file should be replaced...
doCopy = false;
synchronized (this) {
this.notify();
}
}
});
synchronized(uiRunnable) {
// Execute code on UI thread
activity.runOnUiThread(uiRunnable);
// Wait until runnable finished
try {
uiRunnable.wait();
}
catch (InterruptedException e ) {
e.printStackTrace();
}
}
}
// Pos 2. --> Continue work
if (doCopy)
copyFromAToB(File);
}
return null;
}
}
I would expect, that when a conflict is detected the Runnable is executed and and Pos 1 (code inside Runnable to resolve conflict) is executed BEVOR Pos 2 is reached. This is not the case. The Runnable is executed correctly but the AsyncTask does not wait for it to finish. The execution of doInBackground is continued without any interruption. It seems that doInBackground and the Runnable are executed in parallel (not suprising since they are executed on different threads) but why does doInBackground not wait?

Java - Android : Thread being called (run) twice

I would like some help regarding Java - Android MultiThreading
While learning to develop my app in a multi-threading way in order to take advantage of the ever-growing multi-core devices market share (most devices are quad core now, some even octo-core), I ran in a situation where my threads are either being calling twice or running twice.
I just don't why and how.
[EDIT 3]
Alright, I narrowed down the issue : I called the AsyncTask from the onResume() method. Although my app did not lost focus (which would mean a call to onPause() then back to onResume() upon return of focus in which case my threads would be run twice) during the tests, I solved the issue by moving away the call to FetchFriendsList to another place.
So far so good, but since in my tests the app did not loose focus or perhaps it did but I could not witness it (!), I think there is another reason behind so I'd say my problem is not entirely solved ... at least for the moment. It does work though. Perhaps I did solve the issue but I do not know how :(
[end of EDIT 3]
I am implementing last Facebook SDK and I am using it to fetch the end-user friends list, which seems to do the work.
Since I am running this operation in an AsyncTask, I am not using request.executeAsync().
Instead I am using request.executeAndWait(). Facebook JavaDoc does state that this method must only be used if I am not in a the Main UI Thread which is my case otherwise I would get a NetworkOnMainThreadException.
Anyway, this is where the weird behavior is happening.
private final ArrayList<GraphUser> userFriendsList = new ArrayList<GraphUser>();
public final void fetchFriendsList() {
if (this.session != null && this.session.isOpened()) {
final Request requestUserFriendsList = Request.newMyFriendsRequest(
this.session, new Request.GraphUserListCallback()
public final void onCompleted(final List<GraphUser> users, final Response response) {
if (users != null && users.size() > 0) {
Log.v("Retrieved Friends List -> ", String.valueOf(users.size()));
userFriendsList.addAll(users);
}
}
}
);
if (this.asyncFlag)
requestUserFriendsList.executeAsync();
else
requestUserFriendsList.executeAndWait();
}
}
In my case, asyncFlag is set to false because I need to do stuff synchronously in that specific order :
Fetch User Friends List (not on the Main (UI) Thread)
Save friends list on device (separate new thread)
Save friends list on a server (separate new thread)
Following this pattern, the line userFriendsList.addAll(users); is called twice.
In the logcat, the Log.vis showed twice as well, and finally looking with the debugger, the content of the user friends list is made of duplicates.
But that's not all ... step 2 and 3 are indeed two separate threads which are both created and spawned within the same method : public final void asyncSaveFacebookFriendsList().
And guess what, this method is even called twice !
just why ?
At the beginning I was calling the method for step 2 and 3 like this :
[...]
userFriendsList.addAll(users);
asyncSaveFacebookFriendsList(); // it was private before
[...]
This is where the issue started as both line were running twice.
So I thought, alright, I'll call it later like this :
[...]
fetchFriendsList();
asyncSaveFacebookFriendsList(); // it is now public
[...]
But the issue remains still.
If I don't call public final void asyncSaveFacebookFriendsList(), then nothing is run twice.
Why does this issue happen ? Is there something I did not get in Java Threads ?
I do not think this is somehow related to the Facebook SDK because following the same pattern (and doing it also at the same time), I have the same issues when fetching and storing the end-user Twitter friends list.
So I do believe I am doing something wrong. Does someone have any idea in what possible case a thread is called twice ?
Note : all threads are started this way : thread.start(). I am not using any ThreadPool nor the ExecutorService.
In case you need more background context :
Content of AsyncTask : (no need to wonder why Void and Long, I remove the irrelevant code related to it)
private final class FetchFriendsLists extends AsyncTask<Long, Integer, Void> {
protected final Void doInBackground(final Long... params) {
if (params[0] != Long.valueOf(-1)) {
[...]
twitterAPI.fetchUserFriendsList();
publishProgress(1, -1);
}
if (params[1] == Long.valueOf(0)) {
[...]
facebookAPI.fetchFriendsList();
publishProgress(-1, 0);
}
return null;
}
protected final void onProgressUpdate(Integer... flags) {
super.onProgressUpdate(flags);
if (flags[0] != -1)
twitterAPI.asyncSaveFacebookFriendsList();
if (flags[1] == 0)
facebookAPI.asyncSaveFacebookFriendsList();
}
}
As you can see, I start step 2 and 3 in onPublishProgress() which runs on the Main UI Thread. Brefore it was in the doInBackground() method : the issue happens in both cases!
[EDIT]
After further test, it would seem any kind of code is in fact running twice.
I created a simple method called test in which in print a counter. The counter incremente twice as well !
Why you use onProgressUpdate?¿?
onProgressUpdate(Progress...), [...]. This method is used to display any form of progress in the
user interface while the background computation is still executing.
For instance, it can be used to animate a progress bar or show logs in
a text field.
This is used not at the finish of the petition, but when progress increased.
Read this:
http://developer.android.com/reference/android/os/AsyncTask.html
You need to use:
protected void onPostExecute(Long result) {

How to avoid queueEvent at GLSurfaceView in the case of the same thread

I am writing the program which processes Android OpenGL at other thread. But it freezes in case of this code. For example, it processes a method directly without calling task.get(), if it's the same thread. Does such a way exist?
public void onSurfaceCreated(GL10 arg0, EGLConfig arg1)
{
Thread t = new Thread(new Runnable(){
#Override
public void run()
{
FutureTask<Object> task = new FutureTask<Object>(new Callable<Object>() {
#Override
public Object call() {
return null;
}
});
gv.queueEvent(task);
try{
task.get();
}catch(Exception e){
}
Log.i("MainActivity", "Done"); // <- Work
}
});
t.start();
FutureTask<Object> task = new FutureTask<Object>(new Callable<Object>() {
#Override
public Object call() {
return null;
}
});
gv.queueEvent(task);
try{ task.get(); }catch(Exception e){} // <- Freeze
Log.i("MainActivity", "Done");
If I interpret your question correctly, there is some code you would like to run in the OpenGL thread without using a FutureTask, Runnable or other asynchronous solution.
First of all, does this code (and any of its data) depend on other threads? Does it need to be synchronized with other code/data? If yes, then you should use queueEvent() from a different thread. Since you want to stay within the OpenGL thread completely, I assume that your code to be executed does not have any relationship with other (non-GL) threads.
Moreover, never call FutureTask.get() from the same thread as the one which is supposed to perform the FutureTask code -- who will perform the job if your thread is waiting for itself? And if you want to send code to the GL thread from another thread, don't use FutureTask; just use the simple Runnable for it (as an argument to queueEvent()).
Back to the main question: to run something from the GL thread without queueEvent(), you should decide how exactly you want to perform that job, i.e. when (where) exactly it should be called. Do you want to get it called each time onDrawFrame() is called? Or each time onSurfaceChanged() or onSurfaceCreated() is called?
Since you used queueEvent(), I assume you want your code to run before the next upcoming onDrawFrame() call. In the Android GL thread, internally, the order of calls is as follows:
Android processes all your queued events (I simplified this a bit, but the main point is OK)
If needed, Android calls onSurfaceCreated()
If needed, Android calls onSurfaceChanged()
Android calls onDrawFrame()
So, to put it simple, the code you add with queueEvent() will get executed before the next render cycle (onDrawFrame()). If you want to run this code on the GL thread in onDrawFrame(), you can add it to the beginning of onDrawFrame(), for example:
#Override
public void onDrawFrame(GL10 gl) {
if (mDoJob) {
mDoJob = false;
// perform code
}
...
}
Here, mDoJob is a volatile variable. You can set it to true from another thread. However, please be warned that this assumes you don't need any additional synchronization with the other thread that uses the mDoJob signal, i.e. all the code that will run in the mDoJob condition block will be fine without any further synchronization with anything else.
Basically, what I presented above is just a simplified (non-synchronized) solution to replace queueEvent(), which assumes you don't need synchronization (including up-to-date variables as well) with other threads.
If you don't need any signalling (any dependence with other threads), and the value of mDoJob can be decided inside the OpenGL thread (inside onDrawFrame(), onSurfaceCreated() or onSurfaceChanged()), then mDoJob does not need to be volatile. In such a case, you're staying inside the OpenGL thread, so there is no need for an asynchronous (and thus synchronized) solution.
To sum up, specifically, if you want to decide in onSurfaceCreated() whether a code should run in onDrawFrame(), just use a (non-volatile) boolean variable, which you set in onSurfaceCreated(), and then check it in onDrawFrame() (as in my code example above).

How to better unit test Looper and Handler code on Android?

I use the android.os.Handler class to perform tasks on the background. When unit testing these, I call Looper.loop() to make the test thread wait for the background task thread to do its thing. Later, I call Looper.myLooper().quit() (also in the test thread), to allow the test thread to quit the loop and resume the testing logic.
It's all fine and dandy until I want to write more than one test method.
The problem is that Looper doesn't seem to be designed to allow quitting and restarting on the same thread, so I am forced to do all of my testing inside a single test method.
I looked into the source code of Looper, and couldn't find a way around it.
Is there any other way to test my Hander/Looper code? Or maybe some more test friendly way to write my background task class?
The source code for Looper reveals that Looper.myLooper().quit() enqueues a null message in the Message queue, which tells Looper that it is done processing messages FOREVER. Essentially, the thread becomes a dead thread at that point, and there is no way to revive it that I know of. You may have seen error messages when attempting to post messages to the
Handler after quit() is called to the effect "attempting to send message to dead thread". That is what that means.
This can actually be tested easily if you aren't using AsyncTask by introducing a second looper thread (other than the main one created for you implicitly by Android). The basic strategy then is to block the main looper thread using a CountDownLatch while delegating all your callbacks to the second looper thread.
The caveat here is that your code under test must be able to support using a looper other than the default main one. I would argue that this should be the case regardless to support a more robust and flexible design, and it is also fortunately very easy. In general, all that must be done is to modify your code to accept an optional Looper parameter and use that to construct your Handler (as new Handler(myLooper)). For AsyncTask, this requirement makes it impossible to test it with this approach. A problem that I think should be remedied with AsyncTask itself.
Some sample code to get you started:
public void testThreadedDesign() {
final CountDownLatch latch = new CountDownLatch(1);
/* Just some class to store your result. */
final TestResult result = new TestResult();
HandlerThread testThread = new HandlerThread("testThreadedDesign thread");
testThread.start();
/* This begins a background task, say, doing some intensive I/O.
* The listener methods are called back when the job completes or
* fails. */
new ThingThatOperatesInTheBackground().doYourWorst(testThread.getLooper(),
new SomeListenerThatTotallyShouldExist() {
public void onComplete() {
result.success = true;
finished();
}
public void onFizzBarError() {
result.success = false;
finished();
}
private void finished() {
latch.countDown();
}
});
latch.await();
testThread.getLooper().quit();
assertTrue(result.success);
}
I've stumbled in the same issue as yours. I also wanted to make a test case for a class that use a Handler.
Same as what you did, I use the Looper.loop() to have the test thread starts handling the queued messages in the handler.
To stop it, I used the implementation of MessageQueue.IdleHandler to notify me when the looper is blocking to wait the next message to come. When it happen, I call the quit() method. But again, same as you I got a problem when I make more than one test case.
I wonder if you already solved this problem and perhaps care to share it with me (and possibly others) :)
PS: I also would like to know how you call your Looper.myLooper().quit().
Thanks!
Inspired by #Josh Guilfoyle's answer, I decided to try to use reflection to get access to what I needed in order to make my own non-blocking and non-quitting Looper.loop().
/**
* Using reflection, steal non-visible "message.next"
* #param message
* #return
* #throws Exception
*/
private Message _next(Message message) throws Exception {
Field f = Message.class.getDeclaredField("next");
f.setAccessible(true);
return (Message)f.get(message);
}
/**
* Get and remove next message in local thread-pool. Thread must be associated with a Looper.
* #return next Message, or 'null' if no messages available in queue.
* #throws Exception
*/
private Message _pullNextMessage() throws Exception {
final Field _messages = MessageQueue.class.getDeclaredField("mMessages");
final Method _next = MessageQueue.class.getDeclaredMethod("next");
_messages.setAccessible(true);
_next.setAccessible(true);
final Message root = (Message)_messages.get(Looper.myQueue());
final boolean wouldBlock = (_next(root) == null);
if(wouldBlock)
return null;
else
return (Message)_next.invoke(Looper.myQueue());
}
/**
* Process all pending Messages (Handler.post (...)).
*
* A very simplified version of Looper.loop() except it won't
* block (returns if no messages available).
* #throws Exception
*/
private void _doMessageQueue() throws Exception {
Message msg;
while((msg = _pullNextMessage()) != null) {
msg.getTarget().dispatchMessage(msg);
}
}
Now in my tests (which need to run on the UI thread), I can now do:
#UiThreadTest
public void testCallbacks() throws Throwable {
adapter = new UpnpDeviceArrayAdapter(getInstrumentation().getContext(), upnpService);
assertEquals(0, adapter.getCount());
upnpService.getRegistry().addDevice(createRemoteDevice());
// the adapter posts a Runnable which adds the new device.
// it has to because it must be run on the UI thread. So we
// so we need to process this (and all other) handlers before
// checking up on the adapter again.
_doMessageQueue();
assertEquals(2, adapter.getCount());
// remove device, _doMessageQueue()
}
I'm not saying this is a good idea, but so far it's been working for me. Might be worth trying out! What I like about this is that Exceptions that are thrown inside some hander.post(...) will break the tests, which is not the case otherwise.

Categories

Resources