原文地址:http://blog.csdn.net/mao_xiao_feng/article/details/52416439
上篇已经把BaseVRDevice这个类解析了一下,紧接着,摆在我们眼前的问题是既然已经完成了VR设备的基类,那后续的子类必然会对基类做一个相应的扩展,以实现Android和iOS设备所独有的功能。事实上AndroidBaseVRDevice这个类就完成了这些事情,学过android的人都知道一个app的运行最基本的就是Layout和Activity,一个控制前端一个控制后台,而我们本节所要介绍的这个类,就是在BaseVRDevice的基础上,增加了Android所特有的Java对象的创建和Activity的管理,这搭建了一个桥梁,允许我们将Unity和Android两个不同的平台进行通信和交互。
AndroidBaseVRDevice.cs的代码如下,大家可以参照着看看
#if UNITY_ANDROID
using UnityEngine;
using System.Collections.Generic;
public abstract class AndroidBaseVRDevice : BaseVRDevice {
protected AndroidJavaObject cardboardActivity;
public override bool SupportsNativeDistortionCorrection(List<string> diagnostics) {
bool support = base.SupportsNativeDistortionCorrection(diagnostics);
if (cardboardActivity == null) {
diagnostics.Add("Cannot access Activity");
}
return support;
}
public override void Destroy() {
if (cardboardActivity != null) {
cardboardActivity.Dispose();
cardboardActivity = null;
}
base.Destroy();
}
protected virtual void ConnectToActivity() {
try {
using (AndroidJavaClass player = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) {
cardboardActivity = player.GetStatic<AndroidJavaObject>("currentActivity");
}
} catch (AndroidJavaException e) {
cardboardActivity = null;
Debug.LogError("Exception while connecting to the Activity: " + e);
}
}
protected virtual bool CallActivityMethod(string name, params object[] args) {
return CallObjectMethod(cardboardActivity, name, args);
}
protected virtual bool CallActivityMethod<T>(ref T result, string name, params object[] args) {
return CallObjectMethod(ref result, cardboardActivity, name, args);
}
protected AndroidJavaObject Create(string className, params object[] args) {
try {
return new AndroidJavaObject(className, args);
} catch (AndroidJavaException e) {
Debug.LogError("Exception creating object " + className + ": " + e);
return null;
}
}
protected static bool CallObjectMethod(AndroidJavaObject jo, string name, params object[] args) {
if (jo == null) {
Debug.LogError("Object is null when calling method " + name);
return false;
}
try {
jo.Call(name, args);
return true;
} catch (AndroidJavaException e) {
Debug.LogError("Exception calling method " + name + ": " + e);
return false;
}
}
protected static bool CallObjectMethod<T>(ref T result, AndroidJavaObject jo, string name,
params object[] args) {
if (jo == null) {
Debug.LogError("Object is null when calling method " + name);
return false;
}
try {
result = jo.Call<T>(name, args);
return true;
} catch (AndroidJavaException e) {
Debug.LogError("Exception calling method " + name + ": " + e);
return false;
}
}
}
#endif
来自CODE的代码片AndroidBaseVRDevice.cs
/**************************************************************************************************************************************/
代码的第一句就给我们摆了难题,AndroidJavaObject这个类看着像是Android的,但事实上它是Unity库里的一个类,见圣典:
http://www.ceeger.com/Script/AndroidJavaObject/AndroidJavaObject.html
发现这个类下,有一系列函数和一个构造方法static function AndroidJavaObject (className : string, params args : object[])
这个构造方法很有趣,它有两个参数分别是1、指定的Java类名2、传递的参数
为什么说他有趣?
大家可以看一个例子
//创建一个java.lang.String对象,持有该字符串"some string"function Start() {var jo = new AndroidJavaObject("java.lang.String", "some string");}
这是摘自圣典的一个例子,我们通过构造函数将AndroidJavaObject实例化了以后,生成的居然不是AndroidJavaObject的实例而是其字符串参数java.lang.String对象的一个实例。这很神奇,因为我们通常所能认识到的是构造函数构造的一定是类本身,那为什么这里不是?
事实上,我们构造出来的仍然是本身,只不过“看起来”不一样而已。什么是“看起来”不一样呢?
从这里需要引申到Java中所有对象的祖先类,Object类,这里的AndroidJavaObject就是Object类的一个泛型,关于Object类的概念,给一个链接这里不再详述
http://www.cnblogs.com/mengdd/archive/2013/01/03/2842809.html
好了,现在Object作为泛型类,把AndroidJavaObject这个类作为参数来确定具体实例化哪个对象,而实例化哪个对象的问题,就由实例化的AndroidJavaObject类来解答了,所以说,不管是最终实例化的java.lang.String类,还是我们觉得应该实例化的AndroidJavaObject类,都是产自于Object类,它们事实上来源是相同的,而我们只是通过泛型这种手段来将Object对象做了个“变形”。
理解了这一步,我们就知道AndroidJavaObject类在Unity中存在的意义了,它就像一座桥梁,将Java对象与远方的Unity中的对象联系起来。
/**************************************************************************************************************************************/
AndroidJavaClass player = new AndroidJavaClass("com.Unity3D.player.UnityPlayer"
//同理AndroidJavaClass也是如此,只不过它联系了Java中的类和Unity中的类。需要说明的一点是,Class类没有公共构造方法,我们都知道类是对象的抽象,而Class是对Java中所有类的一个抽象,它保存的是一个Java类的元信息,负责类的类型标识问题而从不负责类的实例化问题。于是,我们知道AndroidJavaClass的实例得到的是指定的类型,而不是实例化的对象。附上圣典的介绍:
http://www.ceeger.com/Script/AndroidJavaClass/AndroidJavaClass.html
/**************************************************************************************************************************************/
解决了这个问题,让我们接着往下
using (AndroidJavaClass player = new AndroidJavaClass("com.unity3d.player.UnityPlayer"))
//这一步相当于在Java中引用了名为com.unity3d.player.UnityPlayer的库,而C#与Java互通上面已经说了,一句话就是C#中创建的Java对象需要用到添加到Java语言中的com.unity3d.player.UnityPlayer库中的操作,听起来有些拗口。
cardboardActivity = player.GetStatic<AndroidJavaObject>("currentActivity");
//然后我们接着调用AndroidJavaClass 类下的GetStatic.<FieldType>方法去获取当前的Activity,这句话如果在上一句之前是无法执行的,因为GetStatic.<FieldType>语句是Unity库里的语句,我们正是通过添加了com.unity3d.player.UnityPlayer库才使得该语句可用。说到这里又有人会问了,我们开头的using UnityEngine不是已经将Unity库导入进来了吗?其实using UnityEngine只是将Unity和C#联系起来,但是我们现在做的,是C#环境中,实现Android和Unity的通信,两者显然不一样。
哈哈,这就是编程的魅力:无限的扩展性+严密的逻辑性!
/**************************************************************************************************************************************/
接下去调用对象方法的一些函数和Creat新的对象就不再详述了,无非就是用泛型实现对象内调用其他对象方法,相信大家都能看懂
网友评论