切换Fragment时如何阻止Google Map重新加载?
解决DrawerLayout切换时Google Map重复初始化的问题
你的问题核心在于每次切换导航项时都新建了MapFragment实例,导致每次切回地图页都会重新加载SupportMapFragment,进而触发地图初始化。下面给你两种可行的解决方案,先从最直接的复用Fragment实例开始:
方案一:复用Fragment实例(推荐)
我们在宿主Activity中缓存各个Fragment的实例,切换时直接复用而非新建,同时让MapFragment保留自身状态,避免重建。
第一步:修正宿主Activity的导航逻辑
把导航监听移到Activity中(你的原代码里把导航监听写在MapFragment里是不合理的),并添加Fragment缓存:
class MainActivity : AppCompatActivity() { private lateinit var drawerLayout: DrawerLayout // 用Map缓存已创建的Fragment实例 private val fragmentCache = mutableMapOf<Int, Fragment>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) drawerLayout = findViewById(R.id.drawer_layout) val navigationView: NavigationView = findViewById(R.id.nav_view) // 初始化默认显示的地图Fragment if (savedInstanceState == null) { val mapFragment = MapFragment() fragmentCache[R.id.nav_map] = mapFragment supportFragmentManager.beginTransaction() .replace(R.id.main_activity_frame, mapFragment) .commit() navigationView.setCheckedItem(R.id.nav_map) } navigationView.setNavigationItemSelectedListener { menuItem -> when (menuItem.itemId) { R.id.nav_logout -> { val intent = Intent(this, LoginActivity::class.java) startActivity(intent) true } else -> { // 从缓存取Fragment,不存在才新建 val targetFragment = fragmentCache.getOrPut(menuItem.itemId) { when (menuItem.itemId) { R.id.nav_map -> MapFragment() R.id.nav_forecast -> ForecastFragment() R.id.nav_app_info -> AboutFragment() else -> MapFragment() } } supportFragmentManager.beginTransaction() .replace(R.id.main_activity_frame, targetFragment) .commit() menuItem.isChecked = true drawerLayout.closeDrawers() true } } } } }
第二步:修改MapFragment保留状态
让MapFragment保留自身实例,并复用内部的SupportMapFragment:
class MapFragment : Fragment(), OnMapReadyCallback { private var mMap: GoogleMap? = null private var mapFragment: SupportMapFragment? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 开启实例保留,防止Fragment被销毁重建 retainInstance = true } override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View? { val view = inflater.inflate(R.layout.fragment_map, container, false) // 优先从子Fragment管理器找已存在的SupportMapFragment mapFragment = childFragmentManager.findFragmentById(R.id.map_new) as? SupportMapFragment if (mapFragment == null) { // 仅当不存在时才新建并添加 mapFragment = SupportMapFragment.newInstance() childFragmentManager.beginTransaction() .replace(R.id.map_new, mapFragment!!) .commit() } mapFragment?.getMapAsync(this) return view } override fun onMapReady(googleMap: GoogleMap) { mMap = googleMap // 恢复之前保存的地图状态(比如相机位置) savedInstanceState?.getParcelable<CameraPosition>("camera_position")?.let { mMap?.moveCamera(CameraUpdateFactory.newCameraPosition(it)) } // 你的其他地图初始化逻辑写在这里 } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) // 保存当前地图的相机位置,下次恢复 mMap?.cameraPosition?.let { outState.putParcelable("camera_position", it) } } }
关于WeakReference的思路补充
你提到的WeakReference关联MapView,其实是用来避免内存泄漏的场景(比如在非生命周期持有MapView引用),但在这个问题里,复用Fragment实例的方案已经足够解决重复初始化的问题,不需要额外用WeakReference。如果一定要尝试,核心是在MapFragment中用WeakReference持有MapView,确保Fragment销毁时能正确释放,但这不是解决当前问题的最优解。
内容的提问来源于stack exchange,提问作者dawzaw
相关产品推荐
相关产品推荐

