WebViewCoreThread problem

Put your problem here if it does not fit any of the other categories.

WebViewCoreThread problem

Postby oba » Tue Jan 12, 2010 10:46 am

does anyone knows how to solve this guys problem?
Code: Select all
http://groups.google.com/group/android-developers/browse_thread/thread/c97fe5d3ff603f03/e44990d079cb2fb2?show_docid=e44990d079cb2fb2&fwc=1


i have the same problem, and not sure on how to destroy/properly exit the webView.
oba
Freshman
Freshman
 
Posts: 5
Joined: Wed Dec 03, 2008 8:55 am

Top

Re: WebViewCoreThread problem

Postby potatoho » Sat Feb 19, 2011 10:00 am

I have had the same problem for a while as well. I keep hoping it gets fixed, but I pick up a new device (Droid 2 and old device was Droid Eris) and the issue is still remaining. The main issue is that it drains the battery, and keeps doing it until you kill the WebView owning app. It is a small drain, but perpetual and it seems cumulative.

At first I blamed the other browsers, but I am also seeing it in my application which simply uses a WebView. Only certain web sites trigger it, and ironically the easiest to reproduce it with is google.com.

Just for completeness, here is my setup:

Code: Select all
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setPluginsEnabled(true);
webView.getSettings().setRenderPriority(WebSettings.RenderPriority.HIGH);
webView.getSettings().setAppCacheEnabled(true);
webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
webView.getSettings().setSupportZoom(true);
webView.getSettings().setBuiltInZoomControls(true);


And then I load http://www.google.com

I'm doing no other management of the WebView for pausing or shutdown. Once that page loads, most times I will see a drain of between 0.5% and 3%, even after onStop() or even onDestroy(). This is noticeable if I view it within netmeter's show tasks. If I kill the task the drain stops.

Here's a screenshot of my Droid 2 threads in DDMS. The app is onDestroy() after I ran a WebView pointing to the google site, and yet the app is sucking 1.1% of the CPU activity, second on my netmeter list.

Image

Uploaded with ImageShack.us
potatoho
Experienced Developer
Experienced Developer
 
Posts: 61
Joined: Fri May 21, 2010 9:49 pm

Re: WebViewCoreThread problem

Postby potatoho » Wed Mar 09, 2011 8:04 am

I finally got things under control after several days of research.

Some information, in no particular order:

1) The WebViewCoreThread and other similar entities are going to stick around until your app dies. Unavoidable. The important thing is whether they are consuming CPU cycles. WebViewCoreThread in either wait-timed/native/running status with the utime ticking up is bad. You can attach to your app via DDMS to see the threads.

2) To pause flash you have to call hidden methods WebView.onPause() / WebView.onResume().

3) To pause WebViewCoreThread you use WebView.pauseTimers() / WebView.resumeTimers().

HOWEVER, and this is what took me several days. WebView.pauseTimers() ultimately calls JWebCoreJavaBridge.pause() and if you look at that code it has a reference count. It is important to call pauseTimers() / resumeTimers() in exact pairs -- but what I didn't realize is that JWebCoreJavaBridge.mPauseTimerRefCount is not initialized properly. As such, you have to do ensure that the WebView gets an initial resumeTimers() call so that it will balance properly.

So what you want to do is protect your pauseTimers() / resumeTimers() against unbalanced calls with a local flag, and make sure that you call resumeTimers() when you initialize the WebView. And of course use DDMS to verify the WebViewCoreThread running state during your testing.

Oh, I forgot, also be sure to remove the WebView from your layout and call WebView.destroy() when you are done with it. But be wary of a Motorola bug with a spurious event during the destroy() in some of their added code, so test on Droid X / Droid 2. I wound up putting in a post delayed runnable for the destroy() after a few seconds.
potatoho
Experienced Developer
Experienced Developer
 
Posts: 61
Joined: Fri May 21, 2010 9:49 pm

Re: WebViewCoreThread problem

Postby sa123 » Tue May 10, 2011 7:46 pm

Hi,
I have exactly the same problem with my WebView. I tryed to follow your instructions, but it seems there's something wrong because my webview-threads do not stop.
Could you please post the code of a minimal example in which the webview-threads stop?
Thanx a lot!!!
sa123
Junior Developer
Junior Developer
 
Posts: 11
Joined: Tue May 10, 2011 7:42 pm

Re: WebViewCoreThread problem

Postby potatoho » Tue May 10, 2011 7:55 pm

sa123 wrote:Hi,
I have exactly the same problem with my WebView. I tryed to follow your instructions, but it seems there's something wrong because my webview-threads do not stop.
Could you please post the code of a minimal example in which the webview-threads stop?
Thanx a lot!!!

Unfortunately you can't stop the threads. They will live until your application is killed.

All that you can do is make them go into 'wait'.
potatoho
Experienced Developer
Experienced Developer
 
Posts: 61
Joined: Fri May 21, 2010 9:49 pm

Re: WebViewCoreThread problem

Postby sa123 » Tue May 10, 2011 8:22 pm

Can you show me code which I can make thema wait?

And can you tell me if the wait-status solves my problem, that the webview becomes slower and slower the more webpages I open after an other? I think this is because the threads are running without stop (or wait)?
sa123
Junior Developer
Junior Developer
 
Posts: 11
Joined: Tue May 10, 2011 7:42 pm

Top

Re: WebViewCoreThread problem

Postby potatoho » Tue May 10, 2011 8:35 pm

sa123 wrote:Can you show me code which I can make thema wait?

And can you tell me if the wait-status solves my problem, that the webview becomes slower and slower the more webpages I open after an other? I think this is because the threads are running without stop (or wait)?

I'm not sure if it would cause the webview to get slower. The symptom for me was that it would still consume cycles when I had explicitly paused it.

In your Activity onPause you should call WebView.onPause() and WebView.pauseTimers().
In your Activity onResume you should call WebView.onResume() and WebView.resumeTimers().

But since there is a one-off error in the refcount, you need to call WebView.resumeTimers() when you first create the WebView.

Here is some code:
Code: Select all
private boolean mIsPaused = false;

private void pauseBrowser() {
   if (!mIsPaused) {
      // pause flash and javascript etc
      callHiddenWebViewMethod(mWebView, "onPause");
      mWebView.pauseTimers();
      mIsPaused = true;
   }
}

private void resumeBrowser() {
   if (mIsPaused) {
      // resume flash and javascript etc
      callHiddenWebViewMethod(mWebView, "onResume");
      mWebView.resumeTimers();
      mIsPaused = false;
   }
}

private void callHiddenWebViewMethod(final WebView webview, final String name) {
   try {
      final Method method = WebView.class.getMethod(name);
      method.invoke(webview);
   } catch (final Exception e) {
   }
}
potatoho
Experienced Developer
Experienced Developer
 
Posts: 61
Joined: Fri May 21, 2010 9:49 pm

Re: WebViewCoreThread problem

Postby sa123 » Tue May 10, 2011 9:18 pm

Thanks a lot for your quick reply!!

I did as you told me and added your code at application-onPause and application-onResumen. But my http-threads are still running (don't know why!).
But im not sure if this causes my original problem with the slow webview.

Maybe you have a idea what I do wrong in my application:
I have a list with some different web-links, if I click one item, a new activity with the webview in it is opened and shows the selectd webside. If I open a link after an other the webview becomes slower and anytime there is the message "Web page not available". Any idea what I do wrong?

A big thanx for your help again!!
sa123
Junior Developer
Junior Developer
 
Posts: 11
Joined: Tue May 10, 2011 7:42 pm

Re: WebViewCoreThread problem

Postby potatoho » Tue May 10, 2011 9:27 pm

Are you shutting down your old WebViews?

I do (mWebView is my WebView):

mWebView.stopLoading();
pauseBrowser();
removeView(mWebView); // to remove it from a layout before destroying
mWebView.destroy();
potatoho
Experienced Developer
Experienced Developer
 
Posts: 61
Joined: Fri May 21, 2010 9:49 pm

Re: WebViewCoreThread problem

Postby sa123 » Tue May 10, 2011 9:51 pm

Thanks again.

I'm despearing. Seemed the webview becomes faster, but after about 15 pages the message "Web page not available" was display again.
May I send you my code (only a minimal example)? That woudl be great!
sa123
Junior Developer
Junior Developer
 
Posts: 11
Joined: Tue May 10, 2011 7:42 pm

Re: WebViewCoreThread problem

Postby potatoho » Tue May 10, 2011 10:28 pm

Can you post the code to the thread.
potatoho
Experienced Developer
Experienced Developer
 
Posts: 61
Joined: Fri May 21, 2010 9:49 pm

Re: WebViewCoreThread problem

Postby sa123 » Wed May 11, 2011 5:37 am

main.java:
====================================

public class main extends ListActivity {
private SQLiteDatabase mDatabase; //for my database
private DBManager mHelper; //for my database


@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
mHelper = new DBManager(this); //for my database

ListView lv = getListView();
lv.setOnItemClickListener(new OnItemClickListener() {

public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mDatabase = mHelper.getReadableDatabase();

Intent intentMyWebView = new Intent(main.this, MyWebView.class);
Cursor o = (Cursor) parent.getAdapter().getItem(position);
intentMyWebView.putExtra("name",o.getString(1).toString());
intentMyWebView.putExtra("url",o.getString(2).toString());
startActivity(intentMyWebView);
}
});
}

@Override
protected void onResume() {
super.onResume();

//Get some links from my database
String links_SELECT = "select _id, name, url from links";
mDatabase = mHelper.getReadableDatabase();
Cursor linksCursor = mDatabase.rawQuery(links_SELECT, null);
startManagingCursor(linksCursor);

SimpleCursorAdapter linksAdapter = new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_1, linksCursor,
new String[] { "name" }, new int[] { android.R.id.text1 });
setListAdapter(linksAdapter);
setSelection(0);
}

}



main.xml:
====================================

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical">

<ListView
android:id="@+id/android:list"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />


</LinearLayout>


myWebView.java:
====================================

public class MyWebView extends Activity {
private WebView webview;
final Activity MyActivity = this;
private LinearLayout layout;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.webview);

webview = new WebView(getApplicationContext());
WebSettings webSettings = webview.getSettings();
webSettings.setCacheMode(WebSettings.LOAD_NO_CACHE);

layout = (LinearLayout)findViewById(R.id.linearlayout_webview);
layout.addView(webview, 0);

webview.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});

webview.getSettings().setJavaScriptEnabled(true);
webview.loadUrl(getIntent().getExtras().getString("url"));
}

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
webview.stopLoading();
pauseBrowser();
layout.removeView(webview);
webview.destroy();
finish();
return true;
}
return super.onKeyDown(keyCode, event);
}



@Override
protected void onPause() {
pauseBrowser();
super.onPause();
}

@Override
protected void onResume() {
resumeBrowser();
super.onResume();
}

private boolean mIsPaused = false;

private void pauseBrowser() {
if (!mIsPaused) {
// pause flash and javascript etc
callHiddenWebViewMethod(webview, "onPause");
webview.pauseTimers();
mIsPaused = true;
}
}

private void resumeBrowser() {
if (mIsPaused) {
// resume flash and javascript etc
callHiddenWebViewMethod(webview, "onResume");
webview.resumeTimers();
mIsPaused = false;
}
}

private void callHiddenWebViewMethod(final WebView wv, final String name) {
try {
final Method method = WebView.class.getMethod(name);
method.invoke(webview);
} catch (final Exception e) {
}
}


}


webview.xml:
===============================

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/linearlayout_webview">
</LinearLayout>
sa123
Junior Developer
Junior Developer
 
Posts: 11
Joined: Tue May 10, 2011 7:42 pm

Re: WebViewCoreThread problem

Postby potatoho » Thu May 12, 2011 1:46 am

webview.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
view.loadUrl(url);
return true;
}
});

That seems a bit strange. If you want the WebView to load the url you can just return false from shouldOverrideUrlLoading().

If you want to support other things besides web, such as media etc, you can cut & paste some code from CallbackProxy.java. Something like this..

Code: Select all
      // Taken from CallbackProxy.java
      Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
      intent.addCategory(Intent.CATEGORY_BROWSABLE);
      // If another application is running a WebView and launches the
      // Browser through this Intent, we want to reuse the same window if
      // possible.
      intent.putExtra(Browser.EXTRA_APPLICATION_ID, mContext.getPackageName());
      try {
         mContext.startActivity(intent);
         return true;
      } catch (ActivityNotFoundException ex) {
         // If no application can handle the URL, assume that the
         // browser can handle it.
      }
      // handle this in our WebView
      return super.shouldOverrideUrlLoading(view, url);
potatoho
Experienced Developer
Experienced Developer
 
Posts: 61
Joined: Fri May 21, 2010 9:49 pm

Re: WebViewCoreThread problem

Postby sa123 » Thu May 12, 2011 2:45 pm

I think I don't need the callback proxy, because I only want to open "normal" webpages.

As you suggested, I set the return false in shouldOverrideUrlLoading, but nothing changed.
Don't know what's wrong in my code :-(
sa123
Junior Developer
Junior Developer
 
Posts: 11
Joined: Tue May 10, 2011 7:42 pm

Re: WebViewCoreThread problem

Postby potatoho » Thu May 12, 2011 3:31 pm

I don't see anything obviously wrong. So it works, but it gets slower as you click on links within your list view?

You may have a memory leak, which is sometimes hard to eyeball. It is a situation where certain objects are not GC because there are still lingering references.

A tool I use is called jhat, which is part of the Java SDK I believe.

Go to the DDMS perspective and highlight the app, then click the toolbar button which dumps an hprof file. The hprof file will be saved into your /tmp directory or similar depending on platform. Then run jhat on that hprof file. Jhat will start a little web server which you then browse localhost:7000 to see the objects of your app.

It takes a little practice, but jhat can give you vital information about the relationship of objects and why they are not getting GC.
potatoho
Experienced Developer
Experienced Developer
 
Posts: 61
Joined: Fri May 21, 2010 9:49 pm

Top
Next

Return to Other Coding-Problems

Who is online

Users browsing this forum: Google Feedfetcher and 16 guests