网上找了一些关于在Activity 中传递对象的办法,大多是需要实现 Serializable 或者 Parcelable 接口的。
在我现有的这个项目,需求是会打开很多包含混合 web 页面的activity,不可能为每个混合页面都创建一个 activity原生页面再放置一个 Webview,所以所有的页面都用一个 activity 来呈现,但是变态的需求又来了,每个 web 页面都有一些 js 调用 java 代码的需求,并且每个 web 页面的业务需求也不尽相同 ... 这就有点尴尬了。
我们知道在 android 程序中,webview 里的 js 要调用 android 原生方法,只需要创建一个类,类里写对应公开方法并标注为 JavascriptInterface,再通过 addJavascriptInterface 暴露给 js 即可,在我上几篇文章提到过我当时为了解决这个问题,写了一个 WebFrame 的模块,因为解决 addJavascriptInterface 中的一个参数是 object 不好直接在 activity 中传递而采用了单例的模式,但是今天问题也来了,就是我们的项目会在一个 包含有 webview 的 activity 里再打开一个 包含有 webview 的activity ... 也就是说混合页面嵌套混合页面,并且两个混合页面的业务逻辑不同,这就没办法用单例了 。
回到我当时这个模块中,猛击这里,所有的 List<Object> 都是保存在一个单例中,这对于现在需求简直是个灾难,既然又没办法直接传递 object,并且就算实现了一个实体类实现序列化的接口,里面还是不能有 object,我也不知道为什么,反正就是报错,我的解决办法就是直接传递类名,当然针对所有的 java 层都有一个抽象基类,参见之前写的文章。到 initWebViewObjects 这里我再根据类名动态实例化该类。
protected void initWebViewObjects(WebView webView, ScriptObject scriptObject) {
if (scriptObject == null) return;
WebFrameScriptInterface ws;
try {
ws = (WebFrameScriptInterface) Class.forName(scriptObject.getFullClassName())
.newInstance();
ws.setWebFrameActivity(this);
webView.addJavascriptInterface(ws, scriptObject.getName());
} catch (Exception __) { }
}
ScriptObject 对应的两个成员分别是类的完整路径和 js 调用时的对象名。
private String name;
private String fullClassName;
现在使用方法依然很简单:
Intent intent = new Intent(MainActivity.this, WebFrameActivitySimple.class);
WebFrameSettings frameSettings = new WebFrameSettings();
frameSettings.setUrl("http://euch.com/22.html");
Hello hello = new Hello();
String name = hello.getClass().getName();
frameSettings.setScriptObject(new ScriptObject("hello.test", name));
intent.putExtra("settings", frameSettings);
startActivityForResult(intent, 12);
只不过 Hello 这个类不能再作为内部类了,原理大家都知道。带来的副作用还是提我项目中的实际问题,当时写了一个 QQ 微博的三方登录的功能,在登录成功后会回调执行 WebInterface 类中的 onAuth(int uid) 这个方法,在这个 onAuth 里会关掉针对当前的 Activity 一些操作,比如将 uid 显示在 TextView 上。因为它是内部类,也不需要在类外部进行实例化,所以这一切都没问题。但是现在的 WebInterface 的实例化不在类内部进行了,就需要单独创建一个类了,单独创建的类又不能将 uid 显示在 Activity 类的 TextView 上 ... 纠结,但仔细一想,这不就可以用 startActivityForResult 的方式打开嵌套 WebView 的类嘛,修改 WebInterface 类如下:
public class LoginScriptInterface extends WebFrameScriptInterface {
@JavascriptInterface
public void oauth(String uid) {
int intuid = 0;
try {
intuid = Integer.parseInt(uid);
} catch (Exception ex) {
}
if (intuid > 0) {
Intent intentRs = new Intent();
Bundle bundle = new Bundle();
bundle.putInt("uid", intuid);
intentRs.putExtras(bundle);
getWebFrameActivity().setResult(0x331,intentRs);
getWebFrameActivity().finish();
} else {
getWebFrameActivity().finish();
}
}
}
调用 QQ 登录Activity的方法改成:
Intent intentForQQLogin = new Intent(LoginActivity.this, WebFrameActivity.class);
WebFrameSettings frameSettings = new WebFrameSettings();
frameSettings.setUrl("http://www.xxxxx.com/oauth/qq?client=android");
frameSettings.setTitle("QQ登录");
frameSettings.setNoActionBar(true);
LoginScriptInterface scriptInterface = new LoginScriptInterface();
frameSettings.setScriptObject(new ScriptObject("app", scriptInterface.getClass().getName()));
intentForQQLogin.putExtra("settings", frameSettings);
startActivityForResult(intentForQQLogin, 0x23);
最终问题得以完美解决!
如果你也想使用这个 WebFrame,可以在项目中集成它:
allprojects {
repositories {
...
maven { url 'https://jitpack.io' }
}
}
dependencies {
compile 'com.github.yahch:WebFrame:2017.11.02.4'
}
网友评论