如何用C++Builder实现Androidapi::Jni::Location的LocationListener?
我正在用FireMonkey/C++Builder 11开发首个Android应用,参考Delphi的GPS示例实现LocationListener时遇到两个关键错误,同时不知道如何实现Delphi中的弱引用。
问题详情
错误1:抽象类实例化失败
创建locationListener时执行locationListener = new TLocationListener::TLocationListener();,报错:
[bccaarm Error] HeaderFooterFormwithNavigation.cpp(311): allocating an object of abstract class type 'TLocationListener::TLocationListener'
错误2:类型转换失败
调用requestLocationUpdates时报错:
[bccaarm Error] HeaderFooterFormwithNavigation.cpp(1143): cannot cast 'TLocationListener' to its private base class 'Androidapi::Jni::Location::JLocationListener'
我的现有代码
主窗体代码(FormCreate)
void __fastcall THeaderFooterwithNavigation::FormCreate(TObject *Sender) { if(FLocationManager==NULL) { _di_JLocationManager LocationManager; _di_JObject LocationManagerService = SharedActivityContext()->getSystemService(TJContext::JavaClass->LOCATION_SERVICE); FLocationManager = TJLocationManager::Wrap((_di_IJavaInstance)LocationManagerService); FLocationManager->requestLocationUpdates(TJLocationManager::JavaClass->GPS_PROVIDER,10000,10,locationListener,TJLooper::JavaClass->getMainLooper()); } }
TLocationListener头文件声明
class TLocationListener : public TJavaLocal, JLocationListener { public : __fastcall TLocationListener(); void __fastcall onLocationChanged(JLocation *location); void __fastcall onProviderDisabled(JString provider); void __fastcall onProviderEnabled(JString provider); void __fastcall onStatusChanged(JString provider,int status, JBundle extras); __fastcall ~TLocationListener(); };
解决方案
1. 修正TLocationListener的继承与方法签名
在C++Builder中,实现JNI接口时必须严格匹配方法的调用约定,并且接口继承需要使用公有继承,同时确保所有接口方法正确实现:
// 头文件中修正后的声明 #include <Androidapi.JNIBridge.hpp> #include <Androidapi.Jni.Location.hpp> #include <System.WeakRef.hpp> class THeaderFooterwithNavigation; // 前向声明 class TLocationListener : public TJavaLocal, public JLocationListener // 公有继承JLocationListener { private: TWeakRef<THeaderFooterwithNavigation> FParent; // 实现弱引用 public : __fastcall TLocationListener(THeaderFooterwithNavigation* Parent); void __fastcall onLocationChanged(JLocation* location) override; // 添加override确保方法匹配 void __fastcall onProviderDisabled(JString provider) override; void __fastcall onProviderEnabled(JString provider) override; void __fastcall onStatusChanged(JString provider, jint status, JBundle* extras) override; // 参数类型匹配Java的int(对应jint) __fastcall ~TLocationListener(); };
// cpp文件中的实现 __fastcall TLocationListener::TLocationListener(THeaderFooterwithNavigation* Parent) : TJavaLocal(), FParent(Parent) { } void __fastcall TLocationListener::onLocationChanged(JLocation* location) { // 调用父窗体的位置处理逻辑 if (auto Parent = FParent.Resolve()) { // Parent->HandleLocationChanged(location); } } void __fastcall TLocationListener::onProviderDisabled(JString provider) { // 处理定位Provider禁用逻辑 } void __fastcall TLocationListener::onProviderEnabled(JString provider) { // 处理定位Provider启用逻辑 } void __fastcall TLocationListener::onStatusChanged(JString provider, jint status, JBundle* extras) { // 处理定位状态变化逻辑 } __fastcall TLocationListener::~TLocationListener() { }
2. 修正主窗体代码
在FormCreate中正确初始化监听器,确保参数传递与类型转换正确:
void __fastcall THeaderFooterwithNavigation::FormCreate(TObject *Sender) { if(FLocationManager == NULL) { _di_JObject LocationManagerService = SharedActivityContext()->getSystemService(TJContext::JavaClass->LOCATION_SERVICE); FLocationManager = TJLocationManager::Wrap((_di_IJavaInstance)LocationManagerService); // 初始化监听器 if (locationListener == NULL) { locationListener = new TLocationListener(this); } // 调用requestLocationUpdates,确保监听器类型正确转换 FLocationManager->requestLocationUpdates( TJLocationManager::JavaClass->GPS_PROVIDER, 10000, 10.0f, // 距离参数为float类型,注意与Delphi的整数参数区分 static_cast<_di_JLocationListener>(locationListener), TJLooper::JavaClass->getMainLooper() ); // 获取最后已知位置 _di_JLocation LastLocation = FLocationManager->getLastKnownLocation(TJLocationManager::JavaClass->GPS_PROVIDER); if (LastLocation) { // HandleLocationChanged(LastLocation); } } }
3. 弱引用实现说明
C++Builder中没有Delphi的[weak]属性,可通过TWeakRef类实现弱引用,避免循环引用导致内存泄漏。FParent.Resolve()会返回有效的父指针(若对象未被销毁),否则返回nullptr。
关键注意事项
- 所有JNI接口方法必须添加
override关键字,确保与父类接口签名完全匹配,包括参数类型(如Java的int对应C++的jint)。 - 继承
JLocationListener时必须使用公有继承,否则编译器会禁止向下类型转换。 requestLocationUpdates的距离参数为float类型,不要传入整数,避免参数不匹配。
内容的提问来源于stack exchange,提问作者Tim Beurk

