您好,登錄后才能下訂單哦!
前言
很多復(fù)雜的UI界面,在Android中需要配合大量xml代碼和java代碼實現(xiàn),而使用HTML5可以非常輕松的實現(xiàn)出來,而且具有很好的跨平臺特性,讓我們不必為了多個平臺而重寫代碼,H5學(xué)習(xí)成本也較低,上手快。雖然從目前來說H5在Android系統(tǒng)中的速度可能還欠佳一些,但相信隨著手機的性能不斷的提高,這些問題都會被解決
使用H5開發(fā)Android的UI界面,最重要的就是如何實現(xiàn)Js代碼和Java代碼之間的互相調(diào)用了
在講解之前,讓我們先把項目跑起來
效果圖:
準(zhǔn)備好index.html文件,將它放入Android工程下的assets文件夾中:
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>JSTest</title> <script src="app.js"></script> </head> <body> <table border="1" width="100%" id="table" cellspacing="0"> <tr> <td width="50%" align="center">姓名</td> <td width="50%" align="center">電話</td> </tr> </table> <hr> <input id="jsinput"> <Button onclick="getMessage()">js傳值給Toast</Button> </body> </html>
JavaScript的代碼我單獨寫在一個js文件中了,把app.js文件也放入assets文件夾中:
function getMessage(){ var message = document.getElementById("jsinput"); contact.showToast(message.value); } function addPerson(persons){ var personObjs = eval(persons); var table = document.getElementById("table"); for(var i=0; i < personObjs.length; i++){ var tr = table.insertRow(table.rows.length); var td1 = tr.insertCell(0); td1.align = "center"; var td2 = tr.insertCell(1); td2.align = "center"; td1.innerHTML = personObjs[i].name; td2.innerHTML = personObjs[i].phone; } }
最后就是Java代碼
public class MainActivity extends AppCompatActivity { private WebView mWebView; private Button mJsMethodBtn; private JsObject jsobj; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mJsMethodBtn = (Button) findViewById(R.id.btn_js_method); mWebView = (WebView) findViewById(R.id.web_view); mWebView.loadUrl("file:///android_asset/index.html"); WebSettings setting = mWebView.getSettings(); setting.setJavaScriptEnabled(true); setting.setDefaultTextEncodingName("utf-8"); jsobj = new JsObject(); mWebView.addJavascriptInterface(jsobj, "contact"); mJsMethodBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 添加一個聯(lián)系人 jsobj.addPerson(); } }); } private class JsObject { // 此方法被js調(diào)用 @JavascriptInterface public void showToast(String message) { Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show(); } // 在Web頁面增加一個聯(lián)系人 public void addPerson() { String json = "[{\"name\":\"zwt\",\"phone\":\"15949999999\"}]"; mWebView.loadUrl("javascript:addPerson('" + json + "')"); } } }
還有布局代碼:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#EED5B7" android:orientation="vertical"> <WebView android:id="@+id/web_view" android:layout_width="match_parent" android:layout_height="360dp"/> <Button android:id="@+id/btn_js_method" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="調(diào)用js方法"/> </LinearLayout>
一、JavaScript調(diào)用Android中的方法
這里實現(xiàn)的場景是點擊Web頁面中的Button,把input中輸入的數(shù)據(jù)傳遞給Android系統(tǒng),并通過Toast顯示出來
對應(yīng)的js代碼:
function getMessage(){ var message = document.getElementById("jsinput"); contact.showToast(message.value); }
對應(yīng)的java代碼:
// 此方法被js調(diào)用 @JavascriptInterface public void showToast(String message) { Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show(); }
其中的“contact”其實指的就是我們在java代碼中定義的JsObject類
他倆通過以下方法實現(xiàn)綁定:
mWebView.addJavascriptInterface(jsobj, "contact");
第一個參數(shù)傳入的是一個java對象,第二參數(shù)是指定對應(yīng)的js里調(diào)用該類時需要使用的自定義別名,這個方法的作用就是將一個Java對象和JavaScript聯(lián)系起來
這里需要注意個問題,在SDK17以上的版本中,google為了安全考慮,只允許js調(diào)用帶有@JavascriptInterface注解的Java方法,所以我們要給被js調(diào)用的java方法前加上@JavascriptInterface注解
二、Android調(diào)用JavaScript中的方法
用戶點擊Android中的Button控件后,傳一個json數(shù)據(jù)給JavaScript方法,js解析json數(shù)據(jù)后添加一個新的聯(lián)系人顯示在Web頁面上
對應(yīng)的js代碼:
function addPerson(persons){ var personObjs = eval(persons); var table = document.getElementById("table"); for(var i=0; i < personObjs.length; i++){ var tr = table.insertRow(table.rows.length); var td1 = tr.insertCell(0); td1.align = "center"; var td2 = tr.insertCell(1); td2.align = "center"; td1.innerHTML = personObjs[i].name; td2.innerHTML = personObjs[i].phone; } }
對應(yīng)的java代碼:
// 在Web頁面增加一個聯(lián)系人 public void addPerson() { String json = "[{\"name\":\"zwt\",\"phone\":\"15949999999\"}]"; mWebView.loadUrl("javascript:addPerson('" + json + "')"); }
想要調(diào)用JavaScript中的某個方法,使用以下方法的標(biāo)準(zhǔn)格式就可以了:
mWebView.loadUrl("javascript:xxxMethod()");
“xxxMethod()”指的是JavaScript中的某個方法,如需調(diào)用其它方法,只要把后面的xxxMethod()替換成js中對應(yīng)的方法就好
三、常見問題
1.Android與js互調(diào)不成功
2.網(wǎng)頁的alert彈不出
需要重寫WebChromeClient中的onJsAlert()方法
mWebView.setWebChromeClient(new WebChromeClient() { @Override public boolean onJsAlert(WebView view, String url, String message, JsResult result) { return super.onJsAlert(view, url, message, result); } });
如果需要把web頁面的alert彈出框替換成Android的AlertDialog,可以在onJsAlert()方法里進行重寫,并設(shè)置return為true
3.Js調(diào)用java方法修改UI界面不成功
只要明白這一點:js調(diào)用的java方法,其實是運行在另外一個子線程WebViewCoreThread中
測試一下:把以下語句分別放在Activity的onCreate()方法里和被js調(diào)用的java方法中
Log.e(TAG, "運行線程name->" + Thread.currentThread().getName());
當(dāng)onCreate執(zhí)行時運行的log:
運行線程name->main
當(dāng)JsObject類中的方法運行時的log:
運行線程name->WebViewCoreThread
很明顯,子線程不允許修改主線程UI,所以我們想通過js調(diào)用java代碼直接修改UI界面的做法是不被允許的
如果需要修改,可以通過Handler機制去解決
4.如何讓手機的返回鍵跳到上一個Web頁面
如果不對手機系統(tǒng)的返回鍵進行處理,那么我們按返回鍵會直接關(guān)閉當(dāng)前Activity,而不會回到上一個Web頁面
解決這個問題,我們可以重寫Activity中的onBackPressed()方法:
@Override public void onBackPressed() { super.onBackPressed(); if (mWebView.canGoBack()) { mWebView.goBack(); } else { finish(); } }
總結(jié)
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,如果有疑問大家可以留言交流,謝謝大家對億速云的支持。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。