編輯:關於Android編程
上一篇文章說到,當利用WebViewClient或者WebChromeClient來處理由html頁面傳過來的請求的時候,都會將對應的服務名稱,操作方法和對應的參數數據傳給一個叫PluginManager的類。
PluginManager類的作用是什麼?
大家知道,當利用Android原生環境的功能,比如照像機,比如相冊等,這些功能都是很分散的,說不清楚什麼時候是需要這些功能,什麼時候是不需要這些功能的,所以我們希望能夠像插件一樣,需要的時候就加載進來,不需要的時候不去理他,而PluginManager類就是一個這樣的管理類。
它主要負責幾件事情:
1)進入HTML頁面的時候,去加載我們定義好的控件。
mPluginManager = new PluginManager(this); mPluginManager.loadPlugin();
那麼PluginManager怎麼知道本個應用要加載多少plugin來去響應由Html頁面來的請求呢?
我們是通過一個叫plugin.xml配置文件來定義的。
可以聯想到,Toast和Dialog都是Android原生環境下的顯示窗口,我們雖然用html頁面來實現界面,但是為了保持整個應用的一致性,我們就會用到原生環境中的Toast或者我們自定義的對話框等控件。
需要用到什麼,就在這裡定義什麼。
我們再來看一下loadPlugin方法:
public void loadPlugin() { int identifier = context.getResources().getIdentifier("plugins", "xml", context.getPackageName()); if (identifier == 0) { pluginConfigurationMissing(); } XmlResourceParser xml = context.getResources().getXml(identifier); try { int eventType = -1; while ((eventType = xml.next()) != XmlResourceParser.END_DOCUMENT) { if (eventType == XmlResourceParser.START_TAG) { String name = xml.getName(); if ("plugin".equals(name)) { String pluginName = xml.getAttributeValue(null, "name"); String className = xml.getAttributeValue(null, "class"); configs.put(pluginName, className); } } } } catch (XmlPullParserException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } }
private HashMapconfigs = new HashMap (); private HashMap plugins = new HashMap ();
在這裡,在plugins.xml文件中定義的name屬性就是這個服務名稱。
2)根據請求的服務名稱和操作方法等,為這個請求找到對應的Plugin去處理。String execResult = mPluginManager.exec("service", "action", args);
public String exec(String service, String action, JSONObject args) throws PluginNotFoundException { IPlugin plugin = getPlugin(service); ... PluginResult result = plugin.exec(action, args); ... }
在上面的邏輯可以看到,PluginManager會利用getPlugin方法拿出對應的服務,如下:
public IPlugin getPlugin(String pluginName) throws PluginNotFoundException { String className = configs.get(pluginName); if(className==null){ throw new PluginNotFoundException(pluginName); } if (plugins.containsKey(className)) { return plugins.get(className); } else { return addPlugin(className); } }
IPlugin是一個接口,其定義如下:
public interface IPlugin { public static final String SERVICE = "service"; public static final String ACTION = "action"; public static final String ARGS = "args"; /** * 執行請求 * * @param action * 功能 * @param args * 參數 * @return pluginResult 結果 */ public PluginResult exec(String action, JSONObject args)throws ActionNotFoundException;
public abstract class Plugin implements IPlugin { protected DroidHtml5 context;
比如,我們拿上面的Toast類,其就會繼承Plugin,然後根據對應的服務去實現對應的邏輯,調用原生環境的Toast。
public class Toast extends Plugin { @Override public PluginResult exec(String action, JSONObject args) throws ActionNotFoundException { if ("makeTextShort".equals(action)) { return makeTextShort(args); }else if ("makeTextLong".equals(action)) { return makeTextLong(args); } else { throw new ActionNotFoundException("Toast", action); } } private PluginResult makeTextShort(JSONObject args) { try { String text = args.getString("text"); android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_SHORT).show(); } catch (JSONException e) { e.printStackTrace(); return PluginResult.newErrorPluginResult(e.getMessage()); } return PluginResult.newEmptyPluginResult(); } private PluginResult makeTextLong(JSONObject args) { try { String text = args.getString("text"); android.widget.Toast.makeText(context, text, android.widget.Toast.LENGTH_LONG).show(); } catch (JSONException e) { e.printStackTrace(); return PluginResult.newErrorPluginResult(e.getMessage()); } return PluginResult.newEmptyPluginResult(); } }
3)從Html頁面來調用。
我們在Android原生環境定義了這麼一套Plugin機制,那麼在Html裡面,也可以有這樣的一套接口方法,來對應不同的Plugin,所以我們在javascript中也會定義各種各樣的對象。
比如上面描述的Toast插件,我們可以在javascript中定義一個對應的對象,如下:
var Toast = { makeTextShort : function(text) { return exec("Toast", "makeTextShort", JSON.stringify(text)); }, makeTextLong : function(text) { return exec("Toast", "makeTextLong", JSON.stringify(text)); } }
而在這裡,我們就會將服務名(Toast),操作方法(makeTextShort),還有顯示的內容(JSON.stringfy(text))等通過exec方法,然後利用WebChromeClient的onJsPrompt方法,將命令傳遞給PluginManager,由PluginManager來處理。
public boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result) { System.out.println("onJsPrompt:defaultValue:" + defaultValue + "|" + url + "," + message); JSONObject args = null; JSONObject head = null; try { // message:{"service" : "XX", "action" : "xx"} head = new JSONObject(message); if (defaultValue != null && !defaultValue.equals("")) { try { args = new JSONObject(defaultValue); } catch (Exception e) { e.printStackTrace(); } } String execResult = mPluginManager.exec(head.getString(IPlugin.SERVICE), head.getString(IPlugin.ACTION), args); result.confirm(execResult); return true;
var Toast = { makeTextShort : function(text) { return exec("Toast", "makeTextShort", JSON.stringify(text)); }, makeTextLong : function(text) { return exec("Toast", "makeTextLong", JSON.stringify(text)); } } var Dialog = { ... } var AndroidHtml5 = { .... /* * exec_asyn調用的方法 @params {JSONObject} cmd 服務名和動作命令 @params {String} args 參數 */ callNative : function(cmd, args, success, fail) { .... }, ... callBackJs : function(result,key) { ... } }; /* * Html5與Android同步交互接口 */ var exec = function(service, action, args) { var json = { "service" : service, "action" : action }; var result_str = prompt(JSON.stringify(json), args); var result; try { result = JSON.parse(result_str); } catch (e) { console.error(e.message); } ... } /* * Html5與Android異步交互接口 */ var exec_asyn = function(service, action, args, success, fail) { var json = { "service" : service, "action" : action }; var result = AndroidHtml5.callNative(json, args, success, fail); }
(一).前言:今天我們的項目繼續更新,今天我們主要講解MVP開發模式以及具體實例。 (二).簡介:MVP(Model ViewPrese
相信有很人做的項目估計都用的到這個。就是ListView的下拉刷新上拉加載還有就是列的橫向滾動;PS:橫向滾動帶表頭與固定列(相信蠻多人都有這樣的需求吧?就是在ListV
第一次使用nodejs+ionic+cordova+intellijIdea搭建webApp開發環境,由於nodejs、ionic、cordova、andriod都是第一
說到ListView和GridView大家肯定不陌生,相信也有很多人已經使用到了出神入化的地步,因為這兩個控件實在是太常用了,可以說任何項目都會有ListView的身影,