Android编程权威指南——网页浏览


前言

从Flickr下载的图片都有其关联网页。本章,我们继续升级PhotoGallery应用,让用户点击图片就能看到它的Flickr网页。我们会以两种不同的方式整合网页内容,左边是使用浏览器应用,右边是使用WebView在应用中显示网页内容。


一 最后一段 Flickr 数据

在GalleryItem中添加代码清单30-1所示代码,创建图片URL。
代码清单30-1 添加创建图片URL的代码(GalleryItem.java)

public class GalleryItem {
 private String mCaption;
 private String mId;
 private String mUrl;
 private String mOwner;
 ...
 public void setUrl(String url) {
 mUrl = url;
 }
 public String getOwner() {
 return mOwner;
 }
 public void setOwner(String owner) {
 mOwner = owner;
 }
 public Uri getPhotoPageUri() {
 return Uri.parse("http://www.flickr.com/photos/")
 .buildUpon()
 .appendPath(mOwner)
 .appendPath(mId)
 .build();
 }
 @Override
 public String toString() {
 return mCaption;
 }
} 

以上代码新建了一个mOwner属性,以及一个产生图片URL的getPhotoPageUri()方法。现在,修改parseItems(…)方法,从JSON数据中获取owner属性,如代码清单30-2所示。
代码清单30-2 从JSON数据中获取owner属性(FlickrFetchr.java)

public class FlickrFetchr {
 ...
 private void parseItems(List<GalleryItem> items, JSONObject jsonBody)
 throws IOException, JSONException {
 JSONObject photosJsonObject = jsonBody.getJSONObject("photos");
 JSONArray photoJsonArray = photosJsonObject.getJSONArray("photo");
 for (int i = 0; i < photoJsonArray.length(); i++) {
 JSONObject photoJsonObject = photoJsonArray.getJSONObject(i);
 GalleryItem item = new GalleryItem();
 item.setId(photoJsonObject.getString("id"));
 item.setCaption(photoJsonObject.getString("title"));
 if (!photoJsonObject.has("url_s")) {
 continue;
 }
 item.setUrl(photoJsonObject.getString("url_s"));
 item.setOwner(photoJsonObject.getString("owner"));
 items.add(item);
 }
 }
}

获取图片网页URL的任务就完成了。

二 简单方式:隐式 intent

首先,监听 RecyclerView 显示项的点击事件。更新 PhotoGalleryFragment 类 的
PhotoHolder,实现一个可以发送隐式intent的事件监听方法,如代码清单30-3所示。
代码清单30-3 通过隐式intent实现网页浏览(PhotoGalleryFragment.java)

public class PhotoGalleryFragment extends VisibleFragment {
 ...
 private class PhotoHolder extends RecyclerView.ViewHolder
 implements 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;
 }
 @Override
 public void onClick(View v) {
 Intent i = new Intent(Intent.ACTION_VIEW, mGalleryItem.getPhotoPageUri());
 startActivity(i);
 }
 }
 ...
} 

然后,在PhotoAdapter.onBindViewHolder(…)方法中绑定PhotoHolder给GalleryItem,
如代码清单30-4所示。
代码清单30-4 绑定GalleryItem(PhotoGalleryFragment.java)

private class PhotoAdapter extends RecyclerView.Adapter<PhotoHolder> {
 ...
 @Override
 public void onBindViewHolder(PhotoHolder photoHolder, int position) {
 GalleryItem galleryItem = mGalleryItems.get(position);
 photoHolder.bindGalleryItem(galleryItem);
 Drawable placeholder = getResources().getDrawable(R.drawable.bill_up_close);
 photoHolder.bindDrawable(placeholder);
 mThumbnailDownloader.queueThumbnail(photoHolder, galleryItem.getUrl());
 }
 ...
}

启动PhotoGallery应用并点击任意图片。浏览器应用应该会弹出并加载显示对应的图片网页。

三 较难方式:使用 WebView

创建fragment。新建PhotoPageFragment类,继承上一章的VisibleFragment类。然后,在这个新类中,实例化布局文件,引用WebView,并转发从intent数据中获取的URL,如代码清单30-5所示。
代码清单30-5 创建网页浏览fragment(PhotoPageFragment.java)

public class PhotoPageFragment extends VisibleFragment {
 private static final String ARG_URI = "photo_page_url";
 private Uri mUri;
 private WebView mWebView;
 public static PhotoPageFragment newInstance(Uri uri) {
 Bundle args = new Bundle();
 args.putParcelable(ARG_URI, uri);
 PhotoPageFragment fragment = new PhotoPageFragment();
 fragment.setArguments(args);
 return fragment;
 }
 @Override

public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 mUri = getArguments().getParcelable(ARG_URI);
 }
 @Override
 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;
 }
}

当前,PhotoPageFragment类还未完成,稍后再来完成它。接下来,新建PhotoPageActivity托管类,继承SingleFragmentActivity类,如代码清单30-6所示。
代码清单30-6 创建显示网页的activity(PhotoPageActivity.java)

public class PhotoPageActivity extends SingleFragmentActivity {
 public static Intent newIntent(Context context, Uri photoPageUri) {
 Intent i = new Intent(context, PhotoPageActivity.class);
i.setData(photoPageUri);
 return i;
 }
 @Override
 protected Fragment createFragment() {
 return PhotoPageFragment.newInstance(getIntent().getData());
 }
} 

回到PhotoGalleryFragment类中,弃用隐式intent,启动新建的activity,如代码清单30-7所示。

代码清单30-7 启动新建的activity(PhotoGalleryFragment.java)

public class PhotoGalleryFragment extends VisibleFragment {
 ...
 private class PhotoHolder extends RecyclerView.ViewHolder
 implements View.OnClickListener{
 ...
 @Override
 public void onClick(View v) {
 Intent i = new Intent(Intent.ACTION_VIEW, mGalleryItem.getPhotoPageUri());
 Intent i = PhotoPageActivity
 .newIntent(getActivity(), mGalleryItem.getPhotoPageUri());
 startActivity(i);
 }
 }
  ...
}

最后,在配置文件中声明新建的activity,如代码清单30-8所示。
代码清单30-8 在配置文件中声明activity(AndroidManifest.xml)

<manifest ... >
 ...
 <application
 ...>
 <activity
 android:name=".PhotoGalleryActivity"
 android:label="@string/app_name" >
 ...
 </activity>
 <activity
 android:name=".PhotoPageActivity" />
 <service android:name=".PollService" />
 ...
 </application>
</manifest> 

运行PhotoGallery应用,点击任意图片,可看到一个新的空activity弹出。
首先是告诉WebView要打开的URL。
其次是启用JavaScript。JavaScript默认是禁用的。虽然并不总是需要启用它,但Flickr网站需要。(启用JavaScript后,Android Lint会提示警告信息(担心跨网站的脚本攻击),可以使用@SuppressLint(“SetJavaScriptEnabled”)注解onCreateView(…)方法以禁止Lint的警告。)
最后,需要实现一个WebViewClient类(用来响应WebView上的渲染事件)。添加代码清单30-9所示代码。然后,我们来详细解读PhotoPageFragment类。
代码清单30-9 加载URL(PhotoPageFragment.java)

public class PhotoPageFragment extends VisibleFragment {
 ...
 @Override
 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.getSettings().setJavaScriptEnabled(true);
 mWebView.setWebViewClient(new WebViewClient() {
 mWebView.loadUrl(mUri.toString());
 return v; 
 }
}

为使用ProgressBar,还需使用WebView:WebChromeClient的第二个回调方法。如果说WebViewClient是响应渲染事件的接口,那么WebChromeClient就是一个事件接口,用来响应那些改变浏览器中装饰元素的事件。这包括JavaScript警告信息、网页图标、状态条加载,以及当前网页标题的刷新。在onCreateView(…)方法中,编码实现使用WebChromeClient,如代码清单30-10所示。
代码清单30-10 使用WebChromeClient(PhotoPageFragment.java)

public class PhotoPageFragment extends VisibleFragment {
 ...
 private WebView mWebView;
 private ProgressBar mProgressBar;
 ...
 @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,
 Bundle savedInstanceState) {
 View v = inflater.inflate(R.layout.fragment_photo_page, container, false);
 mProgressBar = (ProgressBar)v.findViewById(R.id.progress_bar);
 mProgressBar.setMax(100); // WebChromeClient reports in range 0-100
 mWebView = (WebView) v.findViewById(R.id.web_view);
 mWebView.getSettings().setJavaScriptEnabled(true);
 mWebView.setWebChromeClient(new WebChromeClient() {
 public void onProgressChanged(WebView webView, int newProgress) {
 if (newProgress == 100) {
 mProgressBar.setVisibility(View.GONE);
  } else {
 mProgressBar.setVisibility(View.VISIBLE);
 mProgressBar.setProgress(newProgress);
 }
 }
 public void onReceivedTitle(WebView webView, String title) {
 AppCompatActivity activity = (AppCompatActivity) getActivity();
 activity.getSupportActionBar().setSubtitle(title);
 }
 });
 mWebView.setWebViewClient(new WebViewClient());
 mWebView.loadUrl(mUri.toString());
 return v;
 }
}

点击任意图片,PhotoPageActivity会出现。网页加载时,会出现进度条,工具栏会出现来自onReceivedTitle(…)方法的子标题。页面加载完毕,进度条随即消失。

四 处理 WebView 的设备旋转问题

为了让PhotoPageActivity自己处理设备配置调整,可在AndroidManifest.xml配置文件中做
如下调整,如代码清单30-11所示。
代码清单30-11 自己处理设备配置更改(AndroidManifest.xml)

<manifest ... >
 ...
 <activity
 android:name=".PhotoPageActivity"
 android:configChanges="keyboardHidden|orientation|screenSize" />
 ...
</manifest>

android:configChanges属性表明,如果因键盘开或关、屏幕方向改变、屏幕大小改变(也包括Android 3.2之后的屏幕方向变化)而发生设备配置更改,那么activity应自己处理配置更改。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值