第三十章 网页浏览
有关实现网页浏览的两种方式
隐式Intent
这种方法直接将URL抛给外部的浏览器来处理:
public void onClick(View view) { Intent i=new Intent(Intent.ACTION_VIEW,mGalleryItem.getPhotoPageUri()); startActivity(i); }
使用WebView
这种方法将这些URL全都交给自己的WebView来处理,要定义这个WebView组件所处的fragment以及托管它的Activity。这些东西都是轻车熟路了,不写了。
现在针对WebView的方法进行总结:
mWebView=(WebView)view.findViewById(R.id.web_view); mWebView.getSettings().setJavaScriptEnabled(true); mWebView.setWebViewClient(new WebViewClient()); mWebView.loadUrl(mUri.toString());
mWebView.getSettings().setJavaScriptEnabled(true);是启用JavaScript;mWebView.setWebViewClient(new WebViewClient());用于响应WebView上的渲染事件;mWebView.loadUrl(mUri.toString());用于加载URL。
WebViewClient()的作用就是去实现例如重定向URL,响应WebView的渲染时间等等需求的类。接下来要用到一个类来优化WebView显示。
WebChromeClient
如果说上面的WebViewClient是响应渲染事件的接口,那么WebChromeClient就是用于响应那些改变浏览器中装饰元素的事件接口(包括JavaScript警告信息、网页图标、状态条加载、网页标题刷新)
下面会调用两个方法来实现状态条加载和网页标题刷新:
mWebView.setWebChromeClient(new WebChromeClient()
{
@Override
public void onProgressChanged(WebView view, int newProgress) {
if (newProgress==100)
{
mProgressBar.setVisibility(View.GONE);
}
else
{
mProgressBar.setVisibility(View.VISIBLE);
mProgressBar.setProgress(newProgress);
}
}
@Override
public void onReceivedTitle(WebView view, String title) {
AppCompatActivity appCompatActivity=(AppCompatActivity)getActivity();
appCompatActivity.getSupportActionBar().setSubtitle(title);
}
});
public void onProgressChanged(WebView view, int newProgress)配合了视图中的有关ProgressBar,来完成状态条;onReceivedTitle直接设置Activity的状态栏子标题。
有关三种fragment处理设备旋转的方式
一开始学的是用onSaveInstanceState来存储数据,实现原理同activity的,每当设备旋转时,它会从头开始加载数据。
在处理asset时介绍了暂时保留fragment实例,这要求fragment能稍后立刻与新建立的activity完成绑定,否则自己也会消失。
上面两种都处理不了保存网页信息的需求,因此介绍了最后一种,也是死到临头的一种方式:让fragment自己处理设备配置的变更。
第三种一听上去就不靠谱,我自己写的fragment,为什么它能教我做事啊。行吧,书上说这么做资源修饰符无法工作了,而且activity/fragment自己处理了设备配置修改了,可能不会去覆盖onSaveInstanceState中存储的UI状态了。
有关挑战练习 使用后退键浏览历史网页
重难点在于怎么在activity中去获取fragment中的WebView。之前学的从fragment返回结果给activity,是利用的startActivityForResult方法,这个方法的问题在于,必须要fragment结束时才有结果返回。这可不行,这显然不行,所以我就用了回调接口的方式:
定义回调接口,并获取实例:
public class PhotoPageFragment extends VisibleFragment { ... private getWebView mGetWebView; public interface getWebView { void getWebView(WebView webView); } ... @Override public void onAttach(@NonNull Context context) { super.onAttach(context); mGetWebView = (getWebView) context; } }
在activity中实现接口:
@Override
public void getWebView(WebView webView) {
mWebView=webView;
}
然后要搞清楚什么时候调用这个接口方法,显然是每当一个网页加载好了之后才能将当前的WebView快照传递给activity嘛。所以重写onPageFinished方法:
mWebView.setWebViewClient(new WebViewClient() { @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); mGetWebView.getWebView(view); } });
然后就是在activity的onBackPressed方法中进行处理:
@Override
public void onBackPressed() {
if (mWebView!=null)
{
if (mWebView.canGoBack())
{
mWebView.goBack();
}
else
{
super.onBackPressed();
}
}
else
{
super.onBackPressed();
}
}
有关挑战练习 非HTTP链接支持
在做这个挑战练习之前,我先是特地地去找了一下有没有这种非http的链接。我也不知道为什么Flickr不想去推广它们的app了,反正我没找到哪里有下载或打开app的链接,我还点了很多个广告,结果都没有。
所以这次挑战练习我也不知道我写的对不对,我借鉴了这个帖子去写的,希望以后有机会能够验证一下。
mWebView.setWebViewClient(new WebViewClient() { ... @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { if (url.indexOf("http")!=-1||url.indexOf("https")!=-1) { return false; } else { Uri uri=Uri.parse(url); Intent i=new Intent(Intent.ACTION_VIEW,uri); startActivity(i); return true; } } });
shouldOverrideUrlLoading方法其实已经被弃用了,但是替代的新方法有版本要求(起码Lollipop),所以我就直接用旧的了。
shouldOverrideUrlLoading返回值为false时让WebViewClient处理,为true时自行解决。