这一章是来讲解网页浏览,我们有两种方式来整合网页内容(1)使用浏览器应用(2)使用WebView在应用中显示网页的内容
一.通过浏览器获得图片对应的URL
(1)对于图片对应的URL,我们能会联想到上面的json内容,感觉应该会需要更多的内容,但实际上我们可以根据官方文档来发现其实网页URL都是有固定的格式的,如下面
http://www.flickr.com/photos/user-id/photo-id
对于上面的全部信息,其实在返回来的json都有,但是需要我们自己去解析出来,然后去拼接起来
查看官方的文档,我们也可以知道json文件中的owner属性值就是用户的ID,那么就可以创建图片的完整URL了
http://www.flickr.com/photos/owner/id
之前已经有了部分从json中获取到一些数据了,所以就直接在GalleryItem中去添加mmOwner属性
private String mOwner;
public String getOwner(){
return mOwner;
}
public void setOwner(String owner) {
mOwner = owner;
}
//增加一个方法来生成图片的URL
public Uri getPhotoPagerUri(){
return Uri.parse("http://www.flickr.com/photos/").buildUpon().appendPath(mOwner).appendPath(mId).build()
}
(2)修改parseItem()方法,从JSON数据中获取owner属性,在方法中添加下面的代码:
item.setOwner(photoJsonObject.getString("owner"));
现在获得图片的URL就已经完成了
(3)使用隐式intent来访问图片URL,隐式intent可以启动浏览器,并在其中打开图片URL指定的网页
首先需要监听RecyclerView的点击事件,更新PhotoGalleryFragment中的PhotoHolder,实现一个可以发送隐式intent的方法
private class PhotoHolder extends RecyclerView.ViewHolder implement View.OnClickListener {
private ImageView mItemImageView;
private GalleryItem mGalleryItem;
public PhotoHolder(View itemView) {
super(itemView);
mItemImageView = (ImageView)itemView.findViewById(R.id.item_image_view);
itemView.setOnClickListener(this);
}
public void bindDrawable(Drawable drawable) {
mItemImageView.setImageDrawable(drawable);
}
public void bindGalleryItem(GalleryItem galleryItem) {
mGalleryItem = galleryItem;
}
public void onClick(View v) {
Intent i = new Intent(Intent.ACTION_VIEW,mGalleryItem.getPhotoPageUri());
startActivity(i);
}
然后在PhotoAdapter.onBindViewHolder()方法中绑定PhotoHolder给GalleryItem
photoHolder.bindGalleryItem(galleryItem);
现在启动应用和点击任意图片,浏览器应用就会弹出加载显示对应的图片网页
二.使用WebView来打开图片的网页URL
通常如果我们不想打开浏览器来显示网页内容,而是想在activity中去显示网页的内容,对于大多数需要帮助文档的应用,常见的做法就是以网页的形式提供帮助文档,这样会方便后期的更新和维护,而打开浏览器查看帮助文档既不专业,也妨碍应用行为的定制,无法将网页整理到自己的用户界面里面去
如果想要在应用中显示网页的内容,那么我们就可以使用WebView类,对于这种方法需要用到下面的行为
(1)首先需要创建一个activity和一个显示WebView的fragment,先按照惯例定义一个名为fragment_photo_page.xml的文件,使用一个ConstraintLayout作为一级组件,在布局编辑框里面安排一个WebView作为一个ConstraintLayout的子组件
添加完WebView,相对于父组件,为每一边添加一个拘束,然后给WebView一个ID
下面是用来创建fragment,新建立PhotoPagerFragment类,继承上一章的VisibleFragment类,然后在这个新类里面实例化布局文件,引用WebView,并转发从intent数据中获取的URL
public class PhotoPagerFragment extends VisibleFragment {
private static final String ARG_URI = "photo_pager_url";
private Uri mUri;
private WebView mWebView;
public static PhotoPagerFragment newInstance(Uri uri) {
Bundle args = new Bundle();
args.putParcelable(ARG_URI,uri);
PhotoPagerFragment fragment = new PhotoPagerFragment();
fragment.setArguments(args);
return fragment;
}
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mUri = getArguments().getParcelable(ARG_URI);
}
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_photo_page,container,false);
mWebView = (WebView)v.findViewById(R.id.web_view);
return v;
}
}
}
此时PhotoPager类还没有完成,接下来就需要来完成它,新建立PhotoPageActivity的托管类,继承SingleFragmentActivity
//创建网页的activity
public class PhotoPagerActivity extends SingleFragmentActivity{
public static Intent newIntent(Context context,Uri PhotoPagerUri) {
Intent i = new Intent(context,PhotoPageActivity.class);
i.setData(photoPagerUri);
return i;
}
protected Fragment createFragment(){
return PhotoPagerFragment.newInstance(getInstance().getData());
}
}
现在放弃隐式intent,然后是启动新建立的activity
Intent i = PhotoPagerActivity.newIntent(getActivity(),mGalleryItem.getPhotoPagerUri());
startActivity(i);
然后这个activity还需要在配置文件中去配置好,这样这个activity才可以使用,不然程序会崩溃
现在启动的话,点击任意图片就会出现一个新的空的activity的出现
三.让WebView来显示Flickr的图片网页,需要完成下面的三件事
(1)首先告诉WebView需要打开的URL
(2)启动JavaScript,JavaScrip默认是禁止的(需要启动时Android Lint就会发起警告,那么对此就可以使用@SuppressLint("SetJavaScriptEndable"))来注解onCreateView()方法以用来禁止Lint的警告
(3)最后需要实现一个WebViewClient类(用来实现WebView的渲染事件)
public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_photo_page,container,false);
mWebView = (WebView)v.findViewById(R.id.web_view);
mWebView.getSetting().setJavaScriptEnabled(true);
//如果没有WebViewClient,那么WebView会要求activity管理器找到一个新的activity来加载新的Url,我们需要在自己的应用中展示网页,那么添加WebViewClient后,按照它的默认实现,它会说:WebView,自己来载入URL吧,这样目标网页就会在WebView里面来打开
mWebView.setWebViewClient(new WebViewClient(){
mWebView.loadUrl(mUril.toString());//加载URL必须等到WebView配置完成后再来进行,这是最后一步
})
return v;
}
四.使用WebChromeClient优化WebView显示
这边我们来优化,为它添加一个标题视图和一个进度条,以视图的方式打开fragment_photo_page.xnl,拖入一个ProgressBar作为第二个子组件,删除WebView最上面的约束,再来设置他们之间的联系
接下来设置WebView的高度为Any Size,设置ProgressBar的高度为wrap_content,宽度为Any Size
最后选中ProgressBar组件,在右边的属性窗口中,将visibility和tools visibility分别设置为gone和visible,最后命名为progress_bar
为了使用ProgressBar,还需要使用WebView:WebChromeClient的第二个回调方法,WebChromeClient是一个事件回调接口,用来响应那些改变了浏览器中装饰元素的事件,包含 JavaScript警告信息,网页图标,状态条加载,以及当前网页标题的刷新
在PhotoPageFragment中添加
private ProgressBar mProgressBar;
在onCreateView方法中添加
mProgressBar = (ProgressBar)v.findViewById(R.id.progress_bar);
mProgressBar.setMax(100);
mWebView.setWebChromeClient(new WebChromeClient(){
public void onProgressChanged(WebView webView,int newProgress) {
if(newProgress == 100) {
mProgressBar.setVisibity(View.GONE);
}esle {
mProgressBar.setVisibility(View.VISIBLE);
mProgressBar.setProgress(newProgress);
}
//状态栏的改变的,变成来自网页的子标题
public void onReceivedTitle(WebView webView,String title) {
AppCompatActivity activity = (AppCompatActivity)getActivity();
Activity.getSupportActionBar().setSubtitle(title);
}
}
})
五.解决WebView的设备旋转问题
如果我们对设备进行了旋转,那么尽管应用工作如常,但是WebView重新加载了网页,这是因为网页数据太多,无法在onSaveInstanceState()里面保存,这边不能按照PhotoPagerFragment的保存,因为WebView是视图层级结构的一部分,所以它旋转肯定会摧毁然后重建,所以对于这些类(如VideoView),Android 推荐让activity自己去处理配置变更,也就是说,无需重新销毁重建activity,就能够直接调整自己的视图用来适应新的屏幕尺寸
需要在AndroidManidest文件里面去,对这个activity里面添加下面的代码
android:configChanges = "keyboardHidden|orientation|screenSize"//