去年有一段時間工作不忙,閑暇之余就自己做了一個閱讀類的應用——《知豆了》,這個應用很簡單,就是通過fiddler抓取豆瓣一刻,知乎日報,一個,每日一文和國家地理等應用的網絡APi,并分析他們的數據,然后將數據應用到自己的應用中去。
應用截圖:
(文章列表)
(文章詳情)
(圖片瀏覽)
做什么?
其實要做的很簡單,我們可以看到圖1是文章列表,這里的數據是豆瓣一刻的Api返回的Json數據,通過解析該數據就可以得到一個圖文混排的列表數據內容,之后再利用ListView的Adapter的getItemViewType方法實現三種不同的item混合調用即可。
之后,圖2是點擊進某個文章后看到的數據內容,這部分內容是Html數據,這個數據有Html代碼也有css代碼,利用的就是WebView來加載網頁的方式達到快速的實現圖文混排的目的,用原生的Android組件是沒辦法很快速很完美的實現這個效果的,所以這是最快的解決方案,但是這個方案就帶來了一個問題,那就是如果我想收藏或者單獨瀏覽這個網頁中的某張圖片便會很困難,因為無法快速的將圖片數據加載到原生的Android組件中去,于是便要想辦法,讓Android原生與Html進行交互,從而達到我們的目的。
其實說到底,我們只要在用戶點擊圖片的時候獲得這個圖片的Url然后將Url告訴我們的安卓圖片組件就可以了,前一步有過web開發經驗的朋友應該都很容易想到,只要利用JavaScript的onClick監聽就可以輕松實現獲取圖片Url的效果,但是如何將獲得Url告訴Android組件,則需要用到Android與JavaScript交互的相關知識了。
怎么做?
因為用到了WebView,那么話不多說了,直接要在Activity中初始化WebView組件才是正事:
mWebView=(WebView) this.findViewById(R.id.news_detail_webView);
之后再對WebView進行初始化設置:
mWebView.getSettings().setLayoutAlgorithm(LayoutAlgorithm.NARROW_COLUMNS);
mWebView.getSettings().setJavaScriptEnabled(true);
mWebView.getSettings().setRenderPriority(RenderPriority.HIGH);
mWebView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); //設置 緩存模式
// 開啟 DOM storage API 功能
mWebView.getSettings().setDomStorageEnabled(true);
//開啟 database storage API 功能
mWebView.getSettings().setDatabaseEnabled(true);
//開啟 Application Caches 功能
mWebView.getSettings().setAppCacheEnabled(true);
mWebView.getSettings().setBlockNetworkImage(false);
mWebView.getSettings().setLoadsImagesAutomatically(true); //自動加載圖片
mWebView.getSettings().setPluginState(PluginState.OFF);
DisplayMetrics metrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(metrics);
設置的具體內容看代碼都能看懂,注意一定要加上setJavaScriptEnabled(true);這個設置,不然的話JavaScript在WebView中都不起作用,還談什么交互呢?
然后在Oncreate方法中繼續加入如下兩行代碼:
mWebView.addJavascriptInterface(new JavascriptInterface(this), "imagelistner");
mWebView.setWebViewClient(new MyWebViewClient());
注意了,這兩行代碼就是Android與JavaScript交互的關鍵。
我們先看第一行代碼:
mWebView.addJavascriptInterface(new JavascriptInterface(this), "imagelistner");
這行代碼的意思就是,給WebView組件加上javaScript的接口,至于接口的內容是什么,接口叫什么名字,方法中的兩個參數就是了。
先看第一個參數,看到可以new就應該知道,這個應該是一個類了,你可以把這個類寫成一個內部類,也可以把它提取成一個獨立的類,現在來看看這個類的內容:
// js通信接口
public class JavascriptInterface {
private Context context;
public JavascriptInterface(Context context) {
this.context = context;
}
public void openImage(String img) {
//
Intent intent = new Intent();
intent.putExtra("image", img);
intent.setClass(context, ShowWebImageActivity.class);
context.startActivity(intent);
}
}
這段代碼就是用來實現程序在點擊后應該執行什么操作的,看代碼可以知道,我是將得到的圖片路徑當作參數傳遞給ShowWebImageActivity的,這個Activity負責的就是根據圖片的Url地址加載圖片。
你可能著急了,這里的代碼也只是交互完畢后的工作內容啊,具體怎么交互啊?
別急,我們來看剛才OnCreate方法的最后一行代碼:
mWebView.setWebViewClient(new MyWebViewClient());
這個方法是用來自定義WebView加載過程中的操作的,具體看 MyWebViewClient 這個類:
// 監聽
private class MyWebViewClient extends WebViewClient {
@Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
return super.shouldOverrideUrlLoading(view, url);
}
@Override
public void onPageFinished(WebView view, String url) {
view.getSettings().setJavaScriptEnabled(true);
super.onPageFinished(view, url);
// html加載完成之后,添加監聽圖片的點擊js函數
addImageClickListner();
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
view.getSettings().setJavaScriptEnabled(true);
super.onPageStarted(view, url, favicon);
}
@Override
public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) {
super.onReceivedError(view, errorCode, description, failingUrl);
}
}
可以看到,大部分都是調用的父類的方法,只是在OnPageFinished這個方法里加入了一個自己的方法,addImageClickListener()方法,這里其實就是交互的關鍵了,我們繼續看這個方法:
// 注入js函數監聽
private void addImageClickListner() {
// 這段js函數的功能就是,遍歷所有的img幾點,并添加onclick函數,
//函數的功能是在圖片點擊的時候調用本地java接口并傳遞url過去
mWebView.loadUrl("javascript:(function(){" +
"var objs = document.getElementsByTagName(\"img\"); " +
"for(var i=0;i<objs.length;i++) " +
"{"
+ " objs[i].onclick=function() " +
" { "
+ " window.imagelistner.openImage(this.src); " +
" } " +
"}" +
"})()");
}
好了,這個就是注入的關鍵了,首先利用WebView的方法loadUrl("javascript:xxx")來實現注入,之后就可以看注入的方法內容了,學過JS的應該很容易理解,其實就是遍歷當前的Html,然后將Html中的Img組件全部獲取到后,再給每個IMG組件加入onClick事件,該事件的方法體就是:
window.imagelistner.openImage(this.src);
注意看這個imagelistenr其實就是 mWebView.addJavascriptInterface(new JavascriptInterface(this), "imagelistner"); 定義的方法名,而openImage就是我們自定義的JavaScriptInterface中的openImage方法。
至此,Android與JavaScript的交互就已經完畢了,點擊WebView中的圖片就可以調用我們原生的Android組件來加載了,想縮放,想下載就隨你啦!