简介:
通过源码,我们来一步步分析Mapbox地图引擎如何进行不同样式的数据加载的,这里是基于5.3.0的版本.
通过官网案例,我们知道在SDK中配置了不同的style样式给我们使用,通过配置不同style,便可加载不同的类型地图,那么我们便可以从setStyleUrl()这个方法着手.这里我们从MapView的setStyleUrl()方法看起
1 2 3 4 5 6 7 8 9 10
| public void setStyleUrl(@NonNull String url) { if (destroyed) { return; } if (!isMapInitialized()) { mapboxMapOptions.styleUrl(url); return; } nativeMapView.setStyleUrl(url); }
|
这里我们看到,他将相关配置直接往下传到底层了,从nativeMapView这个名字可以看出这是一个和原生相关的地图类,那么我们发现即使不传任何style,地图也会初始化一个默认样式的地图,那么这个默认地图是在哪配置的呢,我们使用AndroidStudio的Find Usages功能,我们看到MapboxMap这个类中的onStart()方法也使用了这个方法
1 2 3 4 5 6 7 8
| void onStart() { nativeMapView.update(); trackingSettings.onStart(); if (TextUtils.isEmpty(nativeMapView.getStyleUrl())) { nativeMapView.setStyleUrl(Style.MAPBOX_STREETS); } }
|
我们继续Find Usages这个方法,看看在哪里调用的,我们发现在MapView的initialiseDrawingSurface()方法里初始化画布的同时,也初始化了地图
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| mapRenderer = new GLSurfaceViewMapRenderer(getContext(), glSurfaceView) { @Override public void onSurfaceCreated(GL10 gl, EGLConfig config) { MapView.this.post(new Runnable() { @Override public void run() { if (mapboxMap == null) { initialiseMap(); mapboxMap.onStart(); } } }); super.onSurfaceCreated(gl, config); } };
|
到这里,加载默认样式已经很清晰了,我们继续看nativeMapView.setStyleUrl()方法
1 2 3 4 5 6 7 8
| public void setStyleUrl(String url) { if (isDestroyedOn("setStyleUrl")) { return; } nativeSetStyleUrl(url); } private native void nativeSetStyleUrl(String url);
|
这里我们看到这里将配置简单的往底层传,便没做什么了,这里我们全局搜索一下nativeSetStyleUrl字符串,看到和NativeMapView对应的底层原生文件native_map_view.cpp中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| void NativeMapView::registerNative(jni::JNIEnv& env) { NativeMapView::javaClass = *jni::Class<NativeMapView>::Find(env).NewGlobalRef(env).release(); #define METHOD(MethodPtr, name) jni::MakeNativePeerMethod<decltype(MethodPtr), (MethodPtr)>(name) jni::RegisterNativePeer<NativeMapView>(env, NativeMapView::javaClass, "nativePtr", std::make_unique<NativeMapView, JNIEnv&, jni::Object<NativeMapView>, jni::Object<FileSource>, jni::Object<MapRenderer>, jni::jfloat>, "nativeInitialize", "nativeDestroy", METHOD(&NativeMapView::setStyleUrl, "nativeSetStyleUrl"), ); }
|
这里我们看到这里将setStyleUrl()方法和nativeSetStyleUrl()方法进行绑定,我们看下底层NativeMapView的setStyleUrl()方法
1 2 3
| void NativeMapView::setStyleUrl(jni::JNIEnv& env, jni::String url) { map->getStyle().loadURL(jni::Make<std::string>(env, url)); }
|
这里我们看到它调用了MapView的getStyle()方法,拿到Map::Impl的Style对象,然后调用Style对象的loadURL()方法
1 2 3
| style::Style& Map::getStyle() { return *impl->style; }
|
这里我们看下Style对象的loadURL()方法
1 2 3
| void Style::loadURL(const std::string& url) { impl->loadURL(url); }
|
它又转给它自己的实现类的方法了,这里我们看下Style::Impl的loadURL()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| void Style::Impl::loadURL(const std::string& url_) { lastError = nullptr; observer->onStyleLoading(); loaded = false; url = url_; styleRequest = fileSource.request(Resource::style(url), [this](Response res) { if (res.isFresh() || mutated) { styleRequest.reset(); } if (mutated && loaded) { return; } if (res.error) { const std::string message = "loading style failed: " + res.error->message; Log::Error(Event::Setup, message.c_str()); observer->onStyleError(std::make_exception_ptr(util::StyleLoadException(message))); observer->onResourceError(std::make_exception_ptr(std::runtime_error(res.error->message))); } else if (res.notModified || res.noContent) { return; } else { parse(*res.data); } }); }
|
这里我们看到它首先通知观察者样式正在加载中,然后调用fileSource.request()方法,这里我们看下参数,一个通过Resource的style方法将url分类然后封装成Resource对象,另一个则是回调函数,用于处理获取的响应数据Response
1 2 3 4 5 6
| Resource Resource::style(const std::string& url) { return Resource { Resource::Kind::Style, url }; }
|
这里我们往下看,看看如果处理请求的数据的,我们看到回调函数中有这么一行代码,parse(*res.data);从名字上看,这应该是解析数据的函数,我们看下具体实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| void Style::Impl::parse(const std::string& json_) { Parser parser; if (auto error = parser.parse(json_)) { std::string message = "Failed to parse style: " + util::toString(error); Log::Error(Event::ParseStyle, message.c_str()); observer->onStyleError(std::make_exception_ptr(util::StyleParseException(message))); observer->onResourceError(error); return; } mutated = false; loaded = false; json = json_; sources.clear(); layers.clear(); images.clear(); transitionOptions = {}; transitionOptions.duration = util::DEFAULT_TRANSITION_DURATION; for (auto& source : parser.sources) { addSource(std::move(source)); } for (auto& layer : parser.layers) { addLayer(std::move(layer)); } name = parser.name; defaultCamera.center = parser.latLng; defaultCamera.zoom = parser.zoom; defaultCamera.angle = parser.bearing; defaultCamera.pitch = parser.pitch; setLight(std::make_unique<Light>(parser.light)); spriteLoaded = false; spriteLoader->load(parser.spriteURL, scheduler, fileSource); glyphURL = parser.glyphURL; loaded = true; observer->onStyleLoaded(); }
|
这里我们看到通过Parser.parse()方法将解析的json字符串进行解析,然后进行一些数据的配置,包括数据源,图层,精灵,字体,默认缩放等级和经纬度,方向等等,最后调用onStyleLoaded()方法通知观察者样式加载结束.