Android 如何监听加载完URL的WebView?
我有一个Android 如何监听加载完URL的WebView?,android,android-webview,Android,Android Webview,我有一个WebView,正在从Internet加载页面。我想显示一个ProgressBar,直到加载完成 我如何监听页面加载的完成情况?使用并覆盖扩展和调用(),如下所示: mWebView.setWebViewClient(new WebViewClient() { public void onPageFinished(WebView view, String url) { // do your stuff here } }); 您可以通过类中的方法跟踪进度状
WebView
,正在从Internet加载页面。我想显示一个ProgressBar
,直到加载完成
我如何监听页面加载的完成情况?使用并覆盖扩展和调用(),如下所示:
mWebView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
// do your stuff here
}
});
您可以通过类中的方法跟踪进度状态 初始化进度状态
private int mProgressStatus = 0;
然后,按如下方式加载AsyncTask:
private class Task_News_ArticleView extends AsyncTask<Void, Void, Void> {
private final ProgressDialog dialog = new ProgressDialog(
your_class.this);
// can use UI thread here
protected void onPreExecute() {
this.dialog.setMessage("Loading...");
this.dialog.setCancelable(false);
this.dialog.show();
}
@Override
protected Void doInBackground(Void... params) {
try {
while (mProgressStatus < 100) {
mProgressStatus = webview.getProgress();
}
} catch (Exception e) {
}
return null;
}
protected void onPostExecute(Void result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
}
}
mWebView.setWebViewClient(new WebViewClient() {
private int webViewPreviousState;
private final int PAGE_STARTED = 0x1;
private final int PAGE_REDIRECTED = 0x2;
@Override
public boolean shouldOverrideUrlLoading(WebView view, String urlNewString) {
webViewPreviousState = PAGE_REDIRECTED;
mWebView.loadUrl(urlNewString);
return true;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
webViewPreviousState = PAGE_STARTED;
if (dialog == null || !dialog.isShowing())
dialog = ProgressDialog.show(WebViewActivity.this, "", getString(R.string.loadingMessege), true, true,
new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// do something
}
});
}
@Override
public void onPageFinished(WebView view, String url) {
if (webViewPreviousState == PAGE_STARTED) {
dialog.dismiss();
dialog = null;
}
}
});
私有类任务\u新闻\u文章视图扩展了异步任务{
private final ProgressDialog dialog=新建ProgressDialog(
你的班。这个);
//可以在这里使用UI线程
受保护的void onPreExecute(){
this.dialog.setMessage(“加载…”);
this.dialog.setCancelable(false);
this.dialog.show();
}
@凌驾
受保护的Void doInBackground(Void…参数){
试一试{
而(mProgressStatus<100){
mProgressStatus=webview.getProgress();
}
}捕获(例外e){
}
返回null;
}
受保护的void onPostExecute(void结果){
if(this.dialog.isShowing()){
this.dialog.disclose();
}
}
}
如果要显示进度条,您需要监听进度更改事件,而不仅仅是页面的完成:
mWebView.setWebChromeClient(new WebChromeClient(){
@Override
public void onProgressChanged(WebView view, int newProgress) {
//change your progress bar
}
});
顺便说一句,如果您只想显示一个不确定的进度条,覆盖方法onPageFinished就足够了,这不是100%准确。如果一个页面中有多个iFrame,则会有多个onPageFinished(和onPageStarted)。如果你有几个重定向,它也可能失败。这种方法(几乎)解决了所有问题:
boolean loadingFinished = true;
boolean redirect = false;
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String urlNewString) {
if (!loadingFinished) {
redirect = true;
}
loadingFinished = false;
webView.loadUrl(urlNewString);
return true;
}
@Override
public void onPageStarted(WebView view, String url) {
loadingFinished = false;
//SHOW LOADING IF IT ISNT ALREADY VISIBLE
}
@Override
public void onPageFinished(WebView view, String url) {
if (!redirect) {
loadingFinished = true;
//HIDE LOADING IT HAS FINISHED
} else {
redirect = false;
}
}
});
更新:
WebView webView;
SwipeRefreshLayout _swipe_procesbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_url_page);
String url = "http://stackoverflow.com/";
_swipe_procesbar = (SwipeRefreshLayout)findViewById(R.id.url_path_swipe_procesbar);
_swipe_procesbar.post(new Runnable() {
@Override
public void run() {
_swipe_procesbar.setRefreshing(true);
}
}
);
webView = (WebView) findViewById(R.id.url_page_web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
_swipe_procesbar.setRefreshing(false);
_swipe_procesbar.setEnabled(false);
}
});
webView.loadUrl(url);
}
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/url_path_swipe_procesbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout 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="com.test.test1.UrlPageActivity">
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/url_page_web_view" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
根据文件:
当嵌入帧的内容发生更改时,即单击目标为iframe的链接时,不会调用onPageStarted
我在Twitter上发现了这样一个特殊的例子,只调用了pageFinished,逻辑有点混乱。为了解决这个问题,我添加了一个计划任务,以在X秒后删除加载。在所有其他情况下都不需要这样做
更新2:
现在使用当前的Android WebView实现:
boolean loadingFinished = true;
boolean redirect = false;
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(
WebView view, WebResourceRequest request) {
if (!loadingFinished) {
redirect = true;
}
loadingFinished = false;
webView.loadUrl(request.getUrl().toString());
return true;
}
@Override
public void onPageStarted(
WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
loadingFinished = false;
//SHOW LOADING IF IT ISNT ALREADY VISIBLE
}
@Override
public void onPageFinished(WebView view, String url) {
if (!redirect) {
loadingFinished = true;
//HIDE LOADING IT HAS FINISHED
} else {
redirect = false;
}
}
});
我将的代码简化为:
private class Task_News_ArticleView extends AsyncTask<Void, Void, Void> {
private final ProgressDialog dialog = new ProgressDialog(
your_class.this);
// can use UI thread here
protected void onPreExecute() {
this.dialog.setMessage("Loading...");
this.dialog.setCancelable(false);
this.dialog.show();
}
@Override
protected Void doInBackground(Void... params) {
try {
while (mProgressStatus < 100) {
mProgressStatus = webview.getProgress();
}
} catch (Exception e) {
}
return null;
}
protected void onPostExecute(Void result) {
if (this.dialog.isShowing()) {
this.dialog.dismiss();
}
}
}
mWebView.setWebViewClient(new WebViewClient() {
private int webViewPreviousState;
private final int PAGE_STARTED = 0x1;
private final int PAGE_REDIRECTED = 0x2;
@Override
public boolean shouldOverrideUrlLoading(WebView view, String urlNewString) {
webViewPreviousState = PAGE_REDIRECTED;
mWebView.loadUrl(urlNewString);
return true;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
webViewPreviousState = PAGE_STARTED;
if (dialog == null || !dialog.isShowing())
dialog = ProgressDialog.show(WebViewActivity.this, "", getString(R.string.loadingMessege), true, true,
new OnCancelListener() {
@Override
public void onCancel(DialogInterface dialog) {
// do something
}
});
}
@Override
public void onPageFinished(WebView view, String url) {
if (webViewPreviousState == PAGE_STARTED) {
dialog.dismiss();
dialog = null;
}
}
});
很容易理解,如果上一个回调在onPageStarted上,那么OnPageFinished就完成了,因此页面被完全加载。我非常喜欢@NeTeInStEiN(和@polen)解决方案,但是我会用一个计数器来实现它,而不是使用多个布尔值或状态观察器(这只是另一种风格,但我认为可能是共享的)。它确实有一些细微差别,但我觉得逻辑更容易理解
private void setupWebViewClient() {
webView.setWebViewClient(new WebViewClient() {
private int running = 0; // Could be public if you want a timer to check.
@Override
public boolean shouldOverrideUrlLoading(WebView webView, String urlNewString) {
running++;
webView.loadUrl(urlNewString);
return true;
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
running = Math.max(running, 1); // First request move it to 1.
}
@Override
public void onPageFinished(WebView view, String url) {
if(--running == 0) { // just "running--;" if you add a timer.
// TODO: finished... if you want to fire a method.
}
}
});
}
谢谢你的回答。它帮助了我,但我必须根据我的需要对它进行一些改进。我有几个页面开始和结束,所以我添加了一个计时器,检查是否在页面结束时启动了一个新的页面开始。好吧,糟糕的解释。请参见代码:)
myWebView.setWebViewClient(新的WebViewClient(){
boolean loadingFinished=true;
布尔重定向=假;
长的最后一页开始;
很久以前;
//加载url
公共布尔值shouldOverrideUrlLoading(WebView视图,字符串url){
如果(!加载完成){
重定向=真;
}
loadingFinished=false;
view.loadUrl(url);
返回false;
}
@凌驾
public void onPageStarted(WebView视图、字符串url、位图favicon){
Log.i(“p”、“pagestart”);
loadingFinished=false;
最后一页\u start=System.nanoTime();
显示_splash();
}
//当完成加载页面时
公共void onPageFinished(WebView视图,字符串url){
Log.i(“p”,“pagefinish”);
如果(!重定向){
loadingFinished=true;
}
//在500米塞克内调用清除飞溅
如果(加载完成&&!重定向){
now=System.nanoTime();
新的android.os.Handler().postDelayed(
新的Runnable(){
公开募捐{
清除飞溅物();
}
},
500);
}否则{
重定向=错误;
}
}
私人空位秀_splash(){
if(myWebView.getVisibility()==View.VISIBLE){
设置可见性(View.GONE);
myWebView_splash.setVisibility(View.VISIBLE);
}
}
//如果启动了新的“页面开始”,请不要删除启动屏幕
私有void remove_splash(){
如果(最后一页开始<现在){
设置可见性(View.VISIBLE);
myWebView_splash.setVisibility(View.GONE);
}
}
});
我也找到了一个优雅的解决方案,但没有严格测试:
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (m_webView.getProgress() == 100) {
progressBar.setVisibility(View.GONE);
m_webView.setVisibility(View.VISIBLE);
}
}
使用
SwipeRefreshLayout
和ProgressBar
加载url:UrlPageActivity.java:
WebView webView;
SwipeRefreshLayout _swipe_procesbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_url_page);
String url = "http://stackoverflow.com/";
_swipe_procesbar = (SwipeRefreshLayout)findViewById(R.id.url_path_swipe_procesbar);
_swipe_procesbar.post(new Runnable() {
@Override
public void run() {
_swipe_procesbar.setRefreshing(true);
}
}
);
webView = (WebView) findViewById(R.id.url_page_web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
_swipe_procesbar.setRefreshing(false);
_swipe_procesbar.setEnabled(false);
}
});
webView.loadUrl(url);
}
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/url_path_swipe_procesbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout 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="com.test.test1.UrlPageActivity">
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/url_page_web_view" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
activity\u url\u page.xml:
WebView webView;
SwipeRefreshLayout _swipe_procesbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_url_page);
String url = "http://stackoverflow.com/";
_swipe_procesbar = (SwipeRefreshLayout)findViewById(R.id.url_path_swipe_procesbar);
_swipe_procesbar.post(new Runnable() {
@Override
public void run() {
_swipe_procesbar.setRefreshing(true);
}
}
);
webView = (WebView) findViewById(R.id.url_page_web_view);
webView.getSettings().setJavaScriptEnabled(true);
webView.setWebViewClient(new WebViewClient() {
public void onPageFinished(WebView view, String url) {
_swipe_procesbar.setRefreshing(false);
_swipe_procesbar.setEnabled(false);
}
});
webView.loadUrl(url);
}
<android.support.v4.widget.SwipeRefreshLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/url_path_swipe_procesbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout 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="com.test.test1.UrlPageActivity">
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/url_page_web_view" />
</RelativeLayout>
</android.support.v4.widget.SwipeRefreshLayout>
这里有一种新的方法,用于在URL已加载时通过使用进行检测。使用此模式,我们利用JavaScript对文档状态的了解,在Android运行时内生成本机方法调用。可以使用
@JavaScriptInterface
注释进行这些JavaScript可访问调用
此实现要求我们在WebView
的设置上调用setJavaScriptEnabled(true)
,因此根据应用程序的要求(例如安全问题),它可能不合适
src/io/github/cawfree/webviewcallback/MainActivity.java(果冻豆,API级别16)
res/layout/activity\u main.xml
<?xml version="1.0" encoding="utf-8"?>
<WebView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/webView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
/>
本质上,我们是在附加一个
override fun onLoadResource(WebView view, String url) {
//call loadUrl() method here
// also check if url contains partOfUrl, if not load it differently.
if(url.contains(partOfUrl, true)) {
//it should work if you reach inside this if scope.
} else if(!(currentUrl.startWith("w", true))) {
webView.loadurl("www.$currentUrl")
} else if(!(currentUrl.startWith("h", true))) {
webView.loadurl("https://$currentUrl")
} else { ...}
}
override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
// you can call again loadUrl from here too if there is any error.
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val webView : WebView = findViewById(R.id.webView)
webView.webViewClient = MyWebViewClient()
}
private class MyWebViewClient : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
println("Load Started")
}
override fun onPageFinished(view: WebView, url: String) {
println("Load Finished")
}
}
}
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val webView : WebView = findViewById(R.id.webView)
webView.webViewClient = object : WebViewClient() {
override fun onPageStarted(view: WebView?, url: String?, favicon: Bitmap?) {
println("Load Started")
}
override fun onPageFinished(view: WebView, url: String) {
println("Load Finished")
}
}
}