Question

I have a web view to override the built-in browser and I want to show a progress indicator on the title bar.

This is the code:

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().requestFeature(Window.FEATURE_PROGRESS);

    setContentView(R.layout.browser);
    currentURL = BrowserActivity.this.getIntent().getExtras().getString("currentURL");

    try {
        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new browserActivityClient());
        setProgressBarIndeterminateVisibility(true);
        mWebView.loadUrl(currentURL);
        setProgressBarIndeterminateVisibility(false);
    } catch (Exception e) {
        Log.e(getClass().getSimpleName(), "Browser: " + e.getMessage());
        Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
    } 
}

It should work, I think, according to Android docs and other samples I saw on the net. But it doesn't, could you please tell me where am I wrong?

And another question: if sometimes later I'll choose to declare android:theme="@android:style/Theme.NoTitleBar" in the application manifest, will the progress bar show anymore or not?

Thank you.

Was it helpful?

Solution

In fact the correct code is (tested and working):

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
    requestWindowFeature(Window.FEATURE_PROGRESS);
    currentURL = BrowserActivity.this.getIntent().getExtras().getString("currentURL");

    setContentView(R.layout.browser);

    setProgressBarIndeterminateVisibility(true);
    setProgressBarVisibility(true);

    try {
        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new browserActivityClient());

        mWebView.setWebChromeClient(new WebChromeClient() {
           public void onProgressChanged(WebView view, int progress) {
               setProgress(progress * 100);
              if(progress == 100) {
                 setProgressBarIndeterminateVisibility(false);
                 setProgressBarVisibility(false);
              }
           }
        });
        mWebView.loadUrl(currentURL);
    } catch (Exception e) {
        Log.e(getClass().getSimpleName(), "Browser: " + e.getMessage());
        Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
    } 
}

OTHER TIPS

I got the same problem too.

Because i set the android:theme="@android:style/Theme.NoTitleBar"

I solve it by add a ProgressBar in the layout xml file, such as:

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

<ProgressBar android:id="@+id/progressbar"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="fill_parent"
    android:layout_height="3px"
    android:max="100"
    android:visibility="gone"
/>

<WebView   
    android:id="@+id/webview"  
    android:layout_width="fill_parent"  
    android:layout_height="fill_parent"  
/>  

</LinearLayout>

In code:

// when load url

progressBar.setProgress(0);
progressBar.setVisible(View.VISIBLE);

...

// loading...progress changed

progressBar.setProgress(progress);

...

// when page finish

progressBar.setVisible(View.GONE);

C'est finish!

I have solved the issue.

Your call to setProgressBarVisibility() must be in onStart() or onResume() because, before that point, it seems you are not guaranteed to have any view on which you can change a visibility.


For this incredible solution by Dralangus, here's some fully tested production code. Thank you so much, Dralangus! Finally, a spinner that does not go away upon device rotation.

public class MainActivity extends Activity
{
private static boolean showSpinner; // needs static

public void spinnerOn()
    {
    showSpinner = true;
    setProgressBarIndeterminateVisibility(true);
    }

public void spinnerOff()
    {
    showSpinner = false;
    setProgressBarIndeterminateVisibility(false);
    }

protected void onResume()
    {
    // solved by Dralangus http://stackoverflow.com/a/7414659/294884
    super.onResume();
    if (showSpinner)
        {
        spinnerOn();
        }
    else
        {
        spinnerOff();
        }
    }

protected void onStart()
    {
    super.onStart();
    // note, onResume is called EVEN LATER than onStart,
    // so your most reliable choice is onResume.
    // eternal thanks to Dralangus for this solution
    }

@Override
protected void onCreate(Bundle savedInstanceState)
    {
    super.onCreate(savedInstanceState);
    requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);

    setContentView(R.layout.activity_main);

    ... // Your code
    }

Seeing how some answers mix up the two progress bars, decided to add another answer

These are for the horizontal progress bar at the top

requestWindowFeature(Window.FEATURE_PROGRESS);
setProgressBarIndeterminate(true);
setProgress(intVal);
setProgressBarVisibility(true);

these are for the spinner-style progress bar in the actionbar

requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setProgressBarIndeterminateVisibility(true);

You don't need to request both window features, just the one for the progress type you need.

The mistake in OP's code is caling setProgressBarIndeterminateVisibility(true) having not requested Window.FEATURE_INDETERMINATE_PROGRESS (or vice versa: calling setProgressBarIndeterminateVisibility() instead of setProgressBarVisibility())

It appears that with Android 5.0 (API 21) and above Windows.FEATURE_PROGRESS no longer works. Taking some hints from the response by univasity, I was able to build a progress bar similar to those in other browsers.

activity_main.xml"

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:id="@+id/relativeLayout">

<WebView
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:id="@+id/webView" />

<ProgressBar
    android:id="@+id/progressBar"
    style="?android:attr/progressBarStyleHorizontal"
    android:layout_width="fill_parent"
    android:layout_height="8dp"
    android:max="100"
    android:progressTint="#FF29A8FF"
    android:progressBackgroundTint="#FFFFFFFF"
    android:visibility="gone" />
</FrameLayout>

The FrameLayout allows the progress bar to float above the webview. Setting android:max to 100 makes it align with the default range in the activity, so the values don't have to be converted to the default of 0-10000 otherwise used by the progress bar. android:visibility="gone" makes the progress bar invisible by default.

MainActivty.java:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Get the WebView and the ProgressBar from activity_main.xml.
    final WebView mainWebView = (WebView) findViewById(R.id.webView);
    final ProgressBar progressBar = (ProgressBar) findViewById(R.id.progressBar);

    // Enables JavaScript.
    mainWebView.getSettings().setJavaScriptEnabled(true);

    // Updates the progress bar whenever there are changes and hides it again when it completes.
    mainWebView.setWebChromeClient(new WebChromeClient() {
        public void onProgressChanged(WebView view, int progress) {
            if (progress < 100) {
                    progressBar.setVisibility(View.VISIBLE);
                } else {
                    progressBar.setVisibility(View.GONE);
                }
            progressBar.setProgress(progress);
        }
    });

    // Makes the mainWebView handle all URLs internally instead of calling the default browser.
    mainWebView.setWebViewClient(new WebViewClient());

    // Load a sample URL.
    mainWebView.loadUrl("http://developer.android.com/");
}

WebView.loadUrl is run in a native thread so setProgressBarIndeterminateVisibility(false) gets called immediately pretty much. Also if you use Theme.NoTitleBar the title bar will not be shown and since the progress bar is in the title bar it won't be shown either.

Something like this should work.

public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    getWindow().requestFeature(Window.FEATURE_PROGRESS);

    setContentView(R.layout.browser);
    currentURL = BrowserActivity.this.getIntent().getExtras().getString("currentURL");

    try {
        mWebView = (WebView) findViewById(R.id.webview);
        mWebView.getSettings().setJavaScriptEnabled(true);
        mWebView.setWebViewClient(new browserActivityClient());
        setProgressBarIndeterminateVisibility(true);
        mWebview.setWebChromeClient(new WebChromeClient() {
           public void onProgressChanged(WebView view, int progress) {
              if(progress == 100) {
                 setProgressBarIndeterminateVisibility(false);
              }
           }
        });
        mWebView.loadUrl(currentURL);
    } catch (Exception e) {
        Log.e(getClass().getSimpleName(), "Browser: " + e.getMessage());
        Toast.makeText(this, e.getMessage(), Toast.LENGTH_LONG).show();
    } 
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top