GoogleMap и ViewModel

428 Views Asked by At

I have a screen that contains fragment as a map

XML

<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

    <androidx.appcompat.widget.Toolbar
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:background="@color/design_default_color_background"
            android:fitsSystemWindows="true"
            android:minHeight="?attr/actionBarSize"
            app:theme="@style/ToolbarColoredBackArrow">

        <androidx.constraintlayout.widget.ConstraintLayout
                android:layout_width="match_parent"
                android:layout_height="match_parent">

            <ImageView
                    android:id="@+id/imageView_back"
                    android:layout_width="48dp"
                    android:layout_height="48dp"
                    android:padding="12dp"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent"
                    app:srcCompat="@drawable/back" />

            <TextView
                    android:id="@+id/toolbar_title"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:layout_gravity="center"
                    android:layout_marginStart="8dp"
                    android:layout_marginLeft="8dp"
                    android:layout_marginEnd="8dp"
                    android:layout_marginRight="8dp"
                    android:textColor="@color/colorTextBlack"
                    android:textSize="18sp"
                    app:layout_constraintBottom_toBottomOf="parent"
                    app:layout_constraintEnd_toEndOf="parent"
                    app:layout_constraintStart_toStartOf="parent"
                    app:layout_constraintTop_toTopOf="parent" />

        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.appcompat.widget.Toolbar>

    <fragment
        app:layout_constraintTop_toBottomOf="@id/toolbar"
        app:layout_constraintBottom_toTopOf="@id/ll_bottom"
        android:id="@+id/googleMap"
        class="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        />

    <LinearLayout
        android:id="@+id/ll_bottom"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="4dp"
        android:gravity="center">
        <View
            app:layout_constraintBottom_toBottomOf="parent"
            android:layout_width="100dp"
            android:layout_height="8dp"
            android:background="@drawable/bottom_sheet_divider"/>
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

in OnViewCreated, I first set the map, then set the viewModel and only then I get the bundle and set the value in the viewModel to observe the variable

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        setupMap()

        viewModel = ViewModelProvider(requireActivity(), viewModelFactory).get(MapNewTwoViewModel::class.java)

        setupViewModel()
        getBundle()
    }

there's nothing special about SetupMap

private fun setupMap(){

        val fragment = childFragmentManager.findFragmentById(R.id.googleMap) as SupportMapFragment

        fragment.getMapAsync(this)

    }

override fun onMapReady(map: GoogleMap?) {
        googleMap = map
        googleMap?.uiSettings?.isMyLocationButtonEnabled = true
        googleMap?.uiSettings?.isZoomControlsEnabled = true
        googleMap?.uiSettings?.isCompassEnabled = true
        googleMap?.let {
            setupCluster(googleMap!!)
        }
        googleMap?.setOnMapClickListener {
            if (isClient) {
                viewModel.setType(MapNewTwoViewModel.OrderType.MY)
            } else
                viewModel.setType(MapNewTwoViewModel.OrderType.ALL)

        }
    }

setupCluster

private fun setupCluster(map: GoogleMap) {
        clusterManager = ClusterManager(MyApplication.applicationContext(), map)

        renderer = DotRenderer()
        clusterManager?.renderer = renderer
        if(clusterManager != null){
            Log.d("ClusterManager", "true")
        } else {
            Log.d("ClusterManager", "false")
        }
        map.setOnCameraIdleListener(clusterManager)
        map.setOnMarkerClickListener(clusterManager)
        map.setOnInfoWindowClickListener(clusterManager)


        clusterManager?.setOnClusterClickListener(this)
        clusterManager?.setOnClusterItemClickListener(this)

    }

in setupViewModel i just watching MediatorLiveData

viewModel.mediatorLiveData.observe(viewLifecycleOwner, {
            Log.d("MediatorLiveData", it.size.toString())
            setItemsCluster(it)
        })

setItemsCluster required for clustering

private fun setItemsCluster(orders: List<OrderX>){
        //---somesthing Operation/.
        if(clusterManager == null){
            Log.d("ClusterManager", "null")
        }
        clusterManager?.addItems(itemClusters)
        clusterManager?.cluster()
    }

now logs:

2020-10-21 18:53:23.658 30104-30104/com.app D/ClusterManager: null
2020-10-21 18:53:23.722 30104-30104/com.app D/ClusterManager: true
2020-10-21 18:53:23.734 30104-30104/com.app D/OnClustersChanged: []

Question, why did viewModel.observe() work faster than onMapReady?

After all, I called it later than setupMap (onMapReady, where Cluster is initialized)

And how to fix it? For this reason, I do not add points to ClusterManager

2

There are 2 best solutions below

0
On BEST ANSWER

Set up bindings for the map after it is ready. Like so:

override fun onMapReady(map: GoogleMap?) {
    ...

    setupMapBindings()
}

fun setupMapBindings() {
    viewModel.mediatorLiveData.observe(viewLifecycleOwner, {
        setItemsCluster(it)
    })
}
1
On

getMapAsync is asynchronous (obviously by its name) and takes some time for the map to be ready, when you initially observe LiveData it will return what its current value is so that you always have a value