我想在我的一个Activity中安装SupportMapFragment。我将此片段直接添加到布局xml,并将此布局设置为内容视图。但是当Activity第一次启动时,它需要太长时间(超过1秒)。接下来的发布是好的,需要几毫秒。
我试过了:
但没有任何帮助。显示地图没有任何问题或可疑日志。
您是否有任何建议,原因以及如何改进?
修改 我有一个ListView,当用户点击Item时,它会使用MapFragment启动DetailActivity。单击项目后,在DetailActivity出现之前会有明显的延迟。只有onCreate方法,我调用setContentView,运行时间超过1秒。虽然活动在onCreate方法中,但此活动没有可见内容。点击和显示内容之间的这种延迟不是非常用户友好。
谢谢
答案 0 :(得分:20)
第一次加载需要这么长时间的原因是因为Play服务API必须加载,如日志行所示:
I/Google Maps Android API﹕ Google Play services client version: 6587000
I/Google Maps Android API﹕ Google Play services package version: 6768430
不幸的是,"包"加载和使用MapsInitializer只需要一秒钟就可以获得"客户端。"所以这是一个不那么漂亮的工作:在主启动器活动中初始化一个虚拟地图。
mDummyMapInitializer.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googleMap) {
Log.d(TAG, "onMapReady");
}
});
现在,当您稍后加载实际地图时,它不应该初始化Play服务API。这不应该导致主活动的任何延迟,因为异步方法在主线程上执行。
由于无论如何都必须在某处进行初始化,我认为在应用程序启动时正确执行它是有意义的,这样当您加载实际需要地图的活动时,您根本不需要等待
注意:mDummyMapInitializer
必须是MapFragment
或SupportMapFragment
,必须添加到活动中,否则无法加载Play服务API。还必须从主线程调用getMapAsync
方法本身。
答案 1 :(得分:16)
好的,所以我遇到了同样的问题,并且在查看了这个问题后认为没有“好的”解决方案。
我目前的黑客是延迟添加片段,让活动有机会在添加地图之前渲染其他所有内容。
现在,我将地图嵌入为子片段,因此我的代码如下所示:
// inside onCreateView
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (isAdded()) {
FragmentManager fm = getChildFragmentManager();
GoogleMapFragment mapFragment = GoogleMapFragment
.newInstance();
fm.beginTransaction()
.replace(R.id.mapContainer, mapFragment).commit();
}
}
}, 1000);
如果直接添加到Activity,它可能如下所示:
// inside onCreate
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
if (!isFinishing()) {
FragmentManager fm = getFragmentManager();
GoogleMapFragment mapFragment = GoogleMapFragment
.newInstance();
fm.beginTransaction()
.replace(R.id.mapContainer, mapFragment).commit();
}
}
}, 1000);
然而,需要在Runnable中进行检查,以确保我们不会尝试将地图添加到某些不存在的Activity或Fragment。
我不喜欢像这样的硬编码延迟,所以如果我想出更好的东西,我会回来。 1秒应该是充足的,甚至可能更少。
答案 2 :(得分:11)
我在Application.onCreate()中使用MapsInitializer解决了它:
MapsInitializer.initialize(this);
良好的结果和更清洁(而不是hacky)的解决方案!
答案 3 :(得分:10)
我也一直在与这个问题作斗争,并通过以下方式找到了相当大的改进:
1)拔下USB电缆(或以其他方式断开调试会话)并再次尝试。调试会话处于活动状态时,应用中的Google地图多较慢。断开调试器的连接速度会快得多......它仍然不是最快的,但它至少是可以接受的。
2)除非你已经调用了getMapType()并且确认它与你想要设置的不同,否则不要调用setMapType()。对同一Map类型的多次调用仍会导致每次重置,这可能需要一些时间。
3)以编程方式添加Map片段,类似于@cYrixmorten发布的,但我是从我的onResume()结尾处开始的后台线程开始的,然后等待50ms,然后在UI线程上运行它。这样可以防止它立即触及UI线程,从而为Activity提供加载和显示的时间;你应该至少在屏幕上,而地图可能会阻塞一切。
这里的问题是,您希望每个Activity只创建一个新的MapFragment实例,而不是每次旋转屏幕方向。我所做的是调用“getFragmentManager()。findFragmentById(R.id.mapContainer)”,这将给我上次的地图片段句柄,如果这是第一次给我一个null(在这种情况下我会创建)地图片段并执行FragmentManager.replace())。
答案 4 :(得分:3)
我有一个"主要" activity - 和mapView的活动。当这个activity-with-mapView第一次启动时,它真的很慢。
clocksmith's post给了我一个想法,从一个单独的线程中的主要活动开始初始化。它确实解决了这个问题。
以下是来自" main"的代码。活性:
public void onCreate(Bundle savedInstanceState) {
...
Runnable initMap = () -> {
BaseApplication.d("Start init mapView");
MapView mapView = new MapView(MainActivity.this);
mapView.onCreate(null);
BaseApplication.d("... done");
};
new Thread(initMap).start();
}
从不使用mapView - 它仅用于初始化目的。
这是一个堆栈跟踪 - 仅供参考:
12-09 19:31:54.442 17172-17341/my.app D/XXX: Start init mapView
12-09 19:31:54.525 17172-17341/my.app I/zzy: Making Creator dynamically
12-09 19:31:55.007 17172-17341/my.app D/ChimeraCfgMgr: Reading stored module config
12-09 19:31:55.153 17172-17341/my.app D/ChimeraCfgMgr: Loading module com.google.android.gms.maps from APK /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/MapsModule.apk
12-09 19:31:55.154 17172-17341/my.app D/ChimeraModuleLdr: Loading module APK /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/MapsModule.apk
12-09 19:31:55.262 17172-17341/my.app D/ChimeraFileApk: Primary ABI of requesting process is armeabi-v7a
12-09 19:31:55.271 17172-17341/my.app D/ChimeraFileApk: Classloading successful. Optimized code found.
12-09 19:31:55.316 17172-17341/my.app W/System: ClassLoader referenced unknown path: /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/native-libs/armeabi-v7a
12-09 19:31:55.317 17172-17341/my.app W/System: ClassLoader referenced unknown path: /data/user/0/com.google.android.gms/app_chimera/chimera-module-root/module-71c764a6f3cb92bdc5525a965b589e7c5ed304f3/native-libs/armeabi
12-09 19:31:55.618 17172-17341/my.app I/Google Maps Android API: Google Play services client version: 7571000
12-09 19:31:55.630 17172-17341/my.app I/Google Maps Android API: Google Play services package version: 8489438
12-09 19:31:55.969 17172-17341/my.app I/e: Token loaded from file. Expires in: 423267993 ms.
12-09 19:31:55.969 17172-17341/my.app I/e: Scheduling next attempt in 422967 seconds.
12-09 19:31:56.338 17172-17341/my.app D/XXX: ... done
正如我们所看到的,它确实需要花费很多时间......
答案 5 :(得分:1)
对我而言,因为我使用它的速度比1秒慢:
mapFragment.getMap();
然后我改为:
mapFragment.getMapAsync(new OnMapReadyCallback() {
@Override
public void onMapReady(GoogleMap googleMap) {
map = googleMap;
}
});
使用getMapAsync()不会阻止ui,因此您的活动将在地图之前加载。它仍然很慢,但就我的目的而言,只显示加载消息就可以了。
答案 6 :(得分:1)
与此处的其他解决方案类似,但使用RxJava + RxAndroid。
只需从启动器活动onCreate
调用此代码段即可。
Observable.fromCallable(new Callable<Void>() {
@Override
public Void call() {
MapView mapView = new MapView(LaunchActivity.this); // Replace LaunchActivity with appropriate activity's name
mapView.onCreate(null);
return null;
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(
new Action1<Void>() {
@Override
public void call(Void ignorable) {
Log.i("Google Maps", "Initialised Google Maps.");
}
}, new Action1<Throwable>() {
@Override
public void call(Throwable ignorable) {
Log.w("Google Maps", "[EXPECTED] Initialized Google Maps but got: " + ignorable.getMessage());
}
});
答案 7 :(得分:0)
我遇到了同样的问题,但MapsInitializer的技巧对我不起作用。
以我的拙见,解决该问题的最佳方法是按照其他用户的描述手动加载Map Fragment。这不是一个棘手的解决方案,您只需要处理片段实例
mMapFragment = MapFragment.newInstance();
fragmentManager.beginTransaction().replace(R.id.map_fragment_container, fragment, FRAGMENT_GOOGLEMAPS_TAG).commit();
答案 8 :(得分:0)
这个问题已经存在多年了,但是如果没有一个干净而直接的解决方案,问题仍然存在。我看到了Rx解决方案,但是它不再起作用,所以这里是我的两分钱:
getMapAsync
函数要求您在主线程上调用。因此,将其卸载到Schedulers.io()
线程将不再起作用。null
作为可观察对象的“合法”输出发送,因此我只发送了true
。我的kotlin解决方案存在于主要活动中,在替代函数@AndroidEntryPoint
中被Hilt标注为onCreate(savedInstanceState: Bundle?)
:
val mainThread = AndroidSchedulers.mainThread()
Observable.fromCallable {
val mapView = MapView(this)
mapView.onCreate(null)
true
}.subscribeOn(mainThread).observeOn(mainThread).subscribe(
// on success
{ Log.i("MAPS", "Initialized Google Maps.") },
// on error
{ Log.w("MAPS", "Warming up of Google Maps failed: " + it.message) }
)