Как реализовать размещение карты в реальном времени в android в шаблоне MVVM? - PullRequest
0 голосов
/ 04 февраля 2020

У меня есть это действие, которое содержит фрагмент карты и все методы канала карты

class Maps : AppCompatActivity(), OnMapReadyCallback,
    SharedPreferences.OnSharedPreferenceChangeListener {
    // The BroadcastReceiver used to listen from broadcasts from the service.
    private var myReceiver: MyReceiver? = null
    // A reference to the service used to get location updates.
    private var mService: LocationUpdatesService? = null
    // Tracks the bound state of the service.
    private var mBound = false
    // UI elements.
    private var mRequestLocationUpdatesButton: Button? = null
    private var mRemoveLocationUpdatesButton: Button? = null

    private lateinit var mMap: GoogleMap

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
//        setContentView(R.layout.activity_maps)
        // Obtain the SupportMapFragment and get notified when the map is ready to be used.

        val binding: ActivityMapsBinding =
            DataBindingUtil.setContentView(this, R.layout.activity_maps)

        val viewModel = ViewModelProvider(this).get(MapsViewModel::class.java)

        binding.viewmodel = viewModel

        viewModel.initActivity()

        myReceiver = MyReceiver()
        // Check that the user hasn't revoked permissions by going to Settings.
        if (ServiceUtils.requestingLocationUpdates(this)) {
            if (!checkPermissions()) {
                requestPermissions()
            }
        }
//        lifecycle.addObserver(MapsObserver())
        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)
    }

    // Monitors the state of the connection to the service.
    private val mServiceConnection: ServiceConnection = object : ServiceConnection {
        override fun onServiceConnected(name: ComponentName, service: IBinder) {
            val binder: LocationUpdatesService.LocalBinder = service as LocationUpdatesService.LocalBinder
            mService = binder.service
            mBound = true
        }

        override fun onServiceDisconnected(name: ComponentName) {
            mService = null
            mBound = false
        }
    }


    override fun onStart() {
        super.onStart()
        PreferenceManager.getDefaultSharedPreferences(this)
            .registerOnSharedPreferenceChangeListener(this)
        mRequestLocationUpdatesButton =
            findViewById<View>(R.id.request_location_updates_button) as Button
        mRemoveLocationUpdatesButton =
            findViewById<View>(R.id.remove_location_updates_button) as Button
        mRequestLocationUpdatesButton!!.setOnClickListener {
            if (!checkPermissions()) {
                requestPermissions()
            } else {
                mService!!.requestLocationUpdates()
            }
        }
        mRemoveLocationUpdatesButton!!.setOnClickListener { mService!!.removeLocationUpdates() }
        // Restore the state of the buttons when the activity (re)launches.
        setButtonsState(ServiceUtils.requestingLocationUpdates(this))
        // Bind to the service. If the service is in foreground mode, this signals to the service
// that since this activity is in the foreground, the service can exit foreground mode.
        bindService(
            Intent(this, LocationUpdatesService::class.java), mServiceConnection,
            Context.BIND_AUTO_CREATE
        )
    }

    override fun onResume() {
        super.onResume()
        LocalBroadcastManager.getInstance(this).registerReceiver(
            myReceiver!!,
            IntentFilter(LocationUpdatesService.ACTION_BROADCAST)
        )
    }

    override fun onPause() {
        LocalBroadcastManager.getInstance(this).unregisterReceiver(myReceiver!!)
        super.onPause()
    }

    override fun onStop() {
        if (mBound) { // Unbind from the service. This signals to the service that this activity is no longer
// in the foreground, and the service can respond by promoting itself to a foreground
// service.
            unbindService(mServiceConnection)
            mBound = false
        }
        PreferenceManager.getDefaultSharedPreferences(this)
            .unregisterOnSharedPreferenceChangeListener(this)
        super.onStop()
    }

    /**
     * Returns the current state of the permissions needed.
     */
    private fun checkPermissions(): Boolean {
        return PackageManager.PERMISSION_GRANTED == ActivityCompat.checkSelfPermission(
            this,
            Manifest.permission.ACCESS_FINE_LOCATION
        )
    }

    private fun requestPermissions() {
        val shouldProvideRationale =
            ActivityCompat.shouldShowRequestPermissionRationale(
                this,
                Manifest.permission.ACCESS_FINE_LOCATION
            )
        // Provide an additional rationale to the user. This would happen if the user denied the
// request previously, but didn't check the "Don't ask again" checkbox.
        if (shouldProvideRationale) {
            Log.i(
                TAG,
                "Displaying permission rationale to provide additional context."
            )
            Snackbar.make(
                findViewById(R.id.maps_layout),
                R.string.permission_rationale,
                Snackbar.LENGTH_INDEFINITE
            )
                .setAction(R.string.ok) {
                    // Request permission
                    ActivityCompat.requestPermissions(
                        this@Maps,
                        arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                        REQUEST_PERMISSIONS_REQUEST_CODE
                    )
                }
                .show()
        } else {
            // Request permission. It's possible this can be auto answered if device policy
// sets the permission in a given state or the user denied the permission
// previously and checked "Never ask again".
            ActivityCompat.requestPermissions(
                this@Maps,
                arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
                REQUEST_PERMISSIONS_REQUEST_CODE
            )
        }
    }

    /**
     * Callback received when a permissions request has been completed.
     */
    override fun onRequestPermissionsResult(
        requestCode: Int, permissions: Array<String>,
        grantResults: IntArray
    ) {
        Log.i(TAG, "onRequestPermissionResult")
        if (requestCode == REQUEST_PERMISSIONS_REQUEST_CODE) {
            if (grantResults.size <= 0) { // If user interaction was interrupted, the permission request is cancelled and you
// receive empty arrays.
                Log.i(TAG, "User interaction was cancelled.")
            } else if (grantResults[0] == PackageManager.PERMISSION_GRANTED) { // Permission was granted.
                mService!!.requestLocationUpdates()
            } else { // Permission denied.
                setButtonsState(false)
                Snackbar.make(
                    findViewById(R.id.maps_layout),
                    R.string.permission_denied_explanation,
                    Snackbar.LENGTH_INDEFINITE
                )
                    .setAction(R.string.settings) {
                        // Build intent that displays the App settings screen.
                        val intent = Intent()
                        intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
                        val uri = Uri.fromParts(
                            "package",
                            BuildConfig.APPLICATION_ID, null
                        )
                        intent.data = uri
                        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
                        startActivity(intent)
                    }
                    .show()
            }
        }
    }

    /**
     * Receiver for broadcasts sent by [LocationUpdatesService].
     */
    private inner class MyReceiver() : BroadcastReceiver(){
        override fun onReceive(
            context: Context,
            intent: Intent
        ) {
            val location =
                intent.getParcelableExtra<Location>(LocationUpdatesService.EXTRA_LOCATION)

            if (location != null) {
                Toast.makeText(
                    this@Maps, ServiceUtils.getLocationText(location),
                    Toast.LENGTH_SHORT
                ).show()

                latitude = location.latitude
                longitude = location.longitude
            }
        }
    }

    override fun onSharedPreferenceChanged(
        sharedPreferences: SharedPreferences,
        s: String
    ) { // Update the buttons state depending on whether location updates are being requested.
        if (s == ServiceUtils.KEY_REQUESTING_LOCATION_UPDATES) {
            setButtonsState(
                sharedPreferences.getBoolean(
                    ServiceUtils.KEY_REQUESTING_LOCATION_UPDATES,
                    false
                )
            )
        }
    }

    private fun setButtonsState(requestingLocationUpdates: Boolean) {
        if (requestingLocationUpdates) {
            mRequestLocationUpdatesButton!!.isEnabled = false
            mRemoveLocationUpdatesButton!!.isEnabled = true
        } else {
            mRequestLocationUpdatesButton!!.isEnabled = true
            mRemoveLocationUpdatesButton!!.isEnabled = false
        }
    }

    companion object {
        private val TAG = Maps::class.java.simpleName
        // Used in checking for runtime permissions.
        private const val REQUEST_PERMISSIONS_REQUEST_CODE = 34

        private var latitude: Double = 0.0
        private var longitude: Double =0.0

    }

    override fun onMapReady(googleMap: GoogleMap) {
        mMap = googleMap

        // Add a marker in Sydney and move the camera
        val sydney = LatLng(-34.0, 151.0)
        mMap.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
        mMap.moveCamera(CameraUpdateFactory.newLatLng(sydney))
    }
}

Это модель представления, которую я использую для действия:

 class MapsViewModel() : ViewModel(), OnMapReadyCallback {

    private var googleMap: GoogleMap? = null
    var mMapLatLng = ObservableField<LatLng>()

    fun initMap(context: Context?, mapFragment: SupportMapFragment?){
        mapFragment?.getMapAsync(this)
    }

    @BindingAdapter("initMap")
    fun initMap(mapView: MapView?, latLng: LatLng?) {
        if (mapView != null) {
            mapView.onCreate(Bundle())
            val sydney = LatLng(-34.0, 151.0)
            mapView.getMapAsync(OnMapReadyCallback { googleMap ->
                // Add a marker
                googleMap.addMarker(MarkerOptions().position(sydney).title("Marker in India"))
            })
        }
    }


    fun initActivity(){
        val conn: SocketConnection = SocketConnection()
        conn.initConnection()
    }

    override fun onMapReady(googleMap: GoogleMap?) {
        this.googleMap = googleMap

        // Add a marker in Sydney and move the camera
        val sydney = LatLng(-34.0, 151.0)
        this.googleMap?.addMarker(MarkerOptions().position(sydney).title("Marker in Sydney"))
        this.googleMap?.moveCamera(CameraUpdateFactory.newLatLng(sydney))
    }
}

//Maps Observer

class MapsObserver : LifecycleObserver {

    @OnLifecycleEvent(Lifecycle.Event.ON_CREATE)


    public fun onCreateEvent(){

    }

}

У меня есть служба обновления местоположения в моем пакете услуг. Я довольно озадачен тем, как структурировать все для поддержки шаблона MVVM.

Хорошо ли кодам таким образом поддерживать архитектуру MVVM? Я до сих пор не вызывал внедрение зависимости здесь.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...