Android面试题疑难点

2019-03-31  本文已影响0人  STE北京老徐
image.png

一. Android WebView内处理302重定向

答:开发中处理WebView有面临着以下几个问题:
  1. H5页面在调用Android系统的WebView.goBack()会在一些特殊情况下失效;
    我们需要使用WebView.loadUrl()加载上一个页面的链接来替代调用系统APIWebView.goBack(), 但这样会污染系统内部的URL栈, 所以我们还需要自行维护一个URL栈.
  2. H5页面如有重定向页面, 无法返回上一页.
    需要判断当前链接的状态码, 但WebView中没显式的API来获取当前链接的HTTP Response Code. 但也可以通过一些黑技术来解决.
    首先, 需要着重一下WebViewClient这几个方法:
    onPageStarted
/**
* Notify the host application that a page has started loading. This method
* is called once for each main frame load so a page with iframes or
* framesets will call onPageStarted one time for the main frame. This also
* means that onPageStarted will not be called when the contents of an
* embedded frame changes, i.e. clicking a link whose target is an iframe.
*
* @param view The WebView that is initiating the callback.
* @param url The url to be loaded.
* @param favicon The favicon for this page if it already exists in the
* database.
*/
public void onPageStarted(WebView view, String url, Bitmap favicon) {
}

onPageFinished

/**
* Notify the host application that a page has finished loading. This method
* is called only for main frame. When onPageFinished() is called, the
* rendering picture may not be updated yet. To get the notification for the
* new Picture, use {@link WebView.PictureListener#onNewPicture}.
*
* @param view The WebView that is initiating the callback.
* @param url The url of the page.
*/
public void onPageFinished(WebView view, String url) {
}

shouldOverrideUrlLoading

/**
* Give the host application a chance to take over the control when a new
* url is about to be loaded in the current WebView. If WebViewClient is not
* provided, by default WebView will ask Activity Manager to choose the
* proper handler for the url. If WebViewClient is provided, return true
* means the host application handles the url, while return false means the
* current WebView handles the url.
* This method is not called for requests using the POST "method".
*
* @param view The WebView that is initiating the callback.
* @param url The url to be loaded.
* @return True if the host application wants to leave the current WebView
* and handle the url itself, otherwise return false.
*/
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}

可以在这几个方法中添加打印标记, 来加深对调用顺序的理解

首先确定不可以在onPageFinished中记录URL, 然后在onPageStarted中记录会出现多次记录的问题. 通过打印日志发现, 当链接出现一次重定向时方法shouldOverrideUrlLoading和onPageStarted都会再次被调用, 但onPageFinished只会被调用一次, 所以我们可以根据这一点来记录URL栈.

以下为代码实例:

public class WebClient extends WebViewClient {
/**
 * 记录URL的栈
 * 规则:
 * 1.不可在{@code WebView.onPageFinished();}中开始记录URL;
 * 2.记录需要屏蔽重定向URL.
 */
private final Stack<String> mUrls = new Stack<>();
/**
 * 判断页面是否加载完成
 */
private boolean mIsLoading;
private String mUrlBeforeRedirect;

@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
if (mIsLoading && mUrls.size() > 0) {
mUrlBeforeRedirect = mUrls.pop();
}
recordUrl(url);
this.mIsLoading = true;
}

/**
 * 记录非重定向链接, 避免刷新页面造成的重复入栈
 *
 * @param url 链接
 */
private void recordUrl(String url) {
//这里还可以根据自身业务来屏蔽一些链接被放入URL栈
 if (!TextUtils.isEmpty(url) && !url.equalsIgnoreCase(getLastPageUrl())) {
mUrls.push(url);
} else if (!TextUtils.isEmpty(mUrlBeforeRedirect)) {
mUrls.push(mUrlBeforeRedirect);
mUrlBeforeRedirect = null;
}
}

/**
 * 获取上一页的链接
 **/
private synchronized String getLastPageUrl() {
return mUrls.size() > 0 ? mUrls.peek() : null;
}

/**
 * 推出上一页链接
 */
public String popLastPageUrl() {
if (mUrls.size() >= 2) {
mUrls.pop();//pop current page url
 return mUrls.pop();
}
return null;
}

@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
if (this.mIsLoading || url.startsWith("about:")) {
this.mIsLoading = false;
}
}

@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return false;
}


}

调用方式

WebView web=getWebView();
WebClient client = new WebClient();
web.setWebViewClient(client);
/**
* 返回上一页
* return True表示处理的网页中返回, False表示没有处理返回需要另行处理
**/
public boolean pageGoBack(WebView web, WebClient client) {
final String url = client.popLastPageUrl();
if (url != null) {
web.loadUrl(url);
return true;
}
return false;
}
上一篇下一篇

猜你喜欢

热点阅读