編輯:關於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);
}
Android MVP開發模式詳解(十九)
(一).前言:今天我們的項目繼續更新,今天我們主要講解MVP開發模式以及具體實例。 (二).簡介:MVP(Model ViewPrese
ListView的下拉刷新上拉加載以及帶列的橫向滾動
相信有很人做的項目估計都用的到這個。就是ListView的下拉刷新上拉加載還有就是列的橫向滾動;PS:橫向滾動帶表頭與固定列(相信蠻多人都有這樣的需求吧?就是在ListV
nodejs+ionic+cordova+intellijIdea搭建webApp環境分析
第一次使用nodejs+ionic+cordova+intellijIdea搭建webApp開發環境,由於nodejs、ionic、cordova、andriod都是第一
Android RecyclerView 使用完全解析
說到ListView和GridView大家肯定不陌生,相信也有很多人已經使用到了出神入化的地步,因為這兩個控件實在是太常用了,可以說任何項目都會有ListView的身影,