Моя программа пропускает фреймы, как использовать AsyncTask с Google Maps? - PullRequest
0 голосов
/ 15 мая 2019
My program is skipping frames. I am quite new to kotlin and google maps API. Also if you spot some other problems feel free to point out as I try to figure out the other bugs as well(Unexpected response code 400 for https://clients4.google.com/glm/mmap/api,and my autocomplete fragment pops up and the collapses instantly) 

This is for an application that measures distances between the markers placed on the map by the user. I have tried to implement AsyncTask by transforming some of my functions into async task extensions, but the problem I have encountered is that most of my code interacts with the UI, therefore they can't run on background threads.

This is my MapsActivity code
:



package com.leusoft.decorio

import android.app.Activity
import android.content.Intent
import android.content.IntentSender
import android.content.pm.PackageManager
import android.graphics.Color
import android.location.Address
import android.location.Geocoder
import android.location.Location
import android.os.Bundle
import android.util.Log
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import com.google.android.gms.common.api.ResolvableApiException
import com.google.android.gms.common.api.Status
import com.google.android.gms.location.*
import com.google.android.gms.maps.CameraUpdateFactory
import com.google.android.gms.maps.GoogleMap
import com.google.android.gms.maps.OnMapReadyCallback
import com.google.android.gms.maps.SupportMapFragment
import com.google.android.gms.maps.model.*
import com.google.android.libraries.places.api.Places
import com.google.android.libraries.places.api.model.Place
import com.google.android.libraries.places.widget.Autocomplete
import com.google.android.libraries.places.widget.AutocompleteActivity
import com.google.android.libraries.places.widget.AutocompleteSupportFragment
import com.google.android.libraries.places.widget.listener.PlaceSelectionListener
import com.google.android.libraries.places.widget.model.AutocompleteActivityMode
import com.google.android.material.floatingactionbutton.FloatingActionButton
import java.io.IOException
import java.util.*
import kotlin.collections.ArrayList


class MapsActivity : AppCompatActivity(), OnMapReadyCallback,
    GoogleMap.OnMarkerClickListener, GoogleMap.OnPolylineClickListener {

    private lateinit var lastLocation: Location
    private lateinit var mMap: GoogleMap
    private lateinit var fusedLocationClient: FusedLocationProviderClient
    private lateinit var locationCallback: LocationCallback
    private lateinit var locationRequest: LocationRequest
    private var locationUpdateState = false
    private var markers: ArrayList<LatLng?> = ArrayList(10)
    private var latestMarker: LatLng? = LatLng(0.0, 0.0)
    private lateinit var removeMarker: FloatingActionButton
    private lateinit var removeAll: FloatingActionButton
    private var polylineOptionsArray: ArrayList<PolylineOptions?> = ArrayList(10)

    companion object {
        private const val LOCATION_PERMISSION_REQUEST_CODE = 1
        private const val REQUEST_CHECK_SETTINGS = 2
        private const val AUTOCOMPLETE_REQUEST_CODE = 3

    }


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_maps)

// Получить SupportMapFragment и получить уведомление, когда карта будет готова к использованию

        val mapFragment = supportFragmentManager
            .findFragmentById(R.id.map) as SupportMapFragment
        mapFragment.getMapAsync(this)
        fusedLocationClient = LocationServices.getFusedLocationProviderClient(this)
        locationCallback = object : LocationCallback() {
            override fun onLocationResult(p0: LocationResult) {
                super.onLocationResult(p0)

                lastLocation = p0.lastLocation
            }
        }
        createLocationRequest()
        removeMarker = findViewById(R.id.removeMarker)
        removeAll = findViewById(R.id.removeAll)

// Инициализировать места

        Places.initialize(getApplicationContext(), R.string.google_maps_key.toString())

// Создать новый экземпляр клиента Places

        val placesClient = Places.createClient(this)
        val autocompleteFragment =
            getSupportFragmentManager().findFragmentById(R.id.autocomplete_fragment) as AutocompleteSupportFragment
        autocompleteFragment.setPlaceFields(Arrays.asList(Place.Field.ID, Place.Field.NAME))

        autocompleteFragment.setOnPlaceSelectedListener(PlaceSelectionListener())
    }

    fun PlaceSelectionListener():PlaceSelectionListener? {
        fun onPlaceSelected(place: Place) {
            val fields: List<Place.Field> = Arrays.asList(Place.Field.ID, Place.Field.NAME)

// Начать намерение автозаполнения

            val intent: Intent = Autocomplete.IntentBuilder(
                AutocompleteActivityMode.FULLSCREEN, fields
            )
                .build(this)
            startActivityForResult(intent, AUTOCOMPLETE_REQUEST_CODE)
        }


        fun onError(status: Status) {
            Log.i("Search bar", "An error occurred: " + status)
        }

        return null
    }

// Управляет картой, когда она станет доступной. // Этот обратный вызов срабатывает, когда карта готова к использованию. // Здесь мы можем добавить маркеры или линии, добавить слушателей или переместить камеру. В этом случае // мы просто добавляем маркер возле Сиднея, Австралия. // Если сервисы Google Play не установлены на устройстве, // пользователю будет предложено установить // это внутри SupportMapFragment. Этот метод будет запущен только после того, как пользователь // установил сервисы Google Play и вернулся в приложение.

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

        mMap.uiSettings.isZoomControlsEnabled = true
        mMap.setOnMarkerClickListener(this)
        setUpMap()
    }

    private fun startLocationUpdates() {
        if (ActivityCompat.checkSelfPermission(
                this,
                android.Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION),
                LOCATION_PERMISSION_REQUEST_CODE
            )
            return
        }
        fusedLocationClient.requestLocationUpdates(locationRequest, locationCallback, null /* Looper */)
    }

    private fun clearMap() {
        mMap.clear()
        polylineOptionsArray.clear()
        markers.clear()
    }

    private fun createLocationRequest() {
        locationRequest = LocationRequest()
        locationRequest.interval = 10000
        locationRequest.fastestInterval = 5000
        locationRequest.priority = LocationRequest.PRIORITY_HIGH_ACCURACY

        val builder = LocationSettingsRequest.`enter code here`Builder()
            .addLocationRequest(locationRequest)

        val client = LocationServices.getSettingsClient(this)
        val task = client.checkLocationSettings(builder.build())

        task.addOnSuccessListener {
            locationUpdateState = true
            startLocationUpdates()
        }
        task.addOnFailureListener { e ->
            if (e is ResolvableApiException) {

// Настройки местоположения не удовлетворены, но это можно исправить // показывая пользователю диалог.

                try {

// Показать диалог, вызвав startResolutionForResult (),

// и проверяем результат в onActivityResult ().

                    e.startResolutionForResult(
                        this@MapsActivity,
                        REQUEST_CHECK_SETTINGS
                    )
                } catch (sendEx: IntentSender.SendIntentException) {

// Игнорировать ошибку

                }
            }
        }
    }

    private fun placeMarkerOnMap(location: LatLng) {
        val markerOptions = MarkerOptions().position(location).draggable(true)

        val titleStr = getAddress(location)
        markerOptions.title(titleStr)
        markers.add(location)
        mMap.addMarker(markerOptions)
        latestMarker = location

    }

    override fun onPolylineClick(p0: Polyline?) {
        val start = LatLng(p0!!.points.first().latitude,p0!!.points.first().longitude)
        val end = LatLng(p0!!.points.last().latitude,p0!!.points.last().longitude)
        val polylineOptions:PolylineOptions = PolylineOptions().add(start,end).width(15f).color(Color.RED).clickable(true)
        polylineOptionsArray.remove(polylineOptions)
        p0!!.remove()
    }

    private fun getAddress(latLng: LatLng): String {
        val geocoder = Geocoder(this)
        val addresses: List<Address>?
        val address: Address?
        var addressText = ""

        try {
            addresses = geocoder.getFromLocation(latLng.latitude, latLng.longitude, 1)
            if (null != addresses && !addresses.isEmpty()) {
                address = addresses[0]
                for (i in 0 until address.maxAddressLineIndex) {
                    addressText += if (i == 0) address.getAddressLine(i) else "\n" + address.getAddressLine(i)
                }
            }
        } catch (e: IOException) {
            Log.e("MapsActivity", e.localizedMessage)
        }

        return addressText
    }


    private fun setUpMap() {
        if (ActivityCompat.checkSelfPermission(
                this,
                android.Manifest.permission.ACCESS_FINE_LOCATION
            ) != PackageManager.PERMISSION_GRANTED
        ) {
            ActivityCompat.requestPermissions(
                this,
                arrayOf(android.Manifest.permission.ACCESS_FINE_LOCATION), LOCATION_PERMISSION_REQUEST_CODE
            )
            return
        }
        mMap.isMyLocationEnabled = true

        mMap.mapType = GoogleMap.MAP_TYPE_TERRAIN

        fusedLocationClient.lastLocation.addOnSuccessListener(this) { location ->

// Получил последнее известное местоположение. В некоторых редких ситуациях это может быть нулевым

            if (location != null) {
                lastLocation = location
                val currentLatLng = LatLng(location.latitude, location.longitude)
                mMap.animateCamera(CameraUpdateFactory.newLatLngZoom(currentLatLng, 12f))
            }
        }
        mMap.setOnMapClickListener {
            placeMarkerOnMap(it)
            if (markers.size > 1) {
                val num = markers.size - 2
                val newLinePoint = LatLng(markers[num]!!.latitude, markers[num]!!.longitude)
                polylineOptionsArray.add(
                    PolylineOptions().add(newLinePoint, it).width(15f).color(Color.RED).clickable(true)
                )
                mMap.addPolyline(polylineOptionsArray.last())
            }
            markers.add(it)

        }
        mMap.setOnMarkerClickListener { onMarkerClick(it) }
        mMap.setOnPolylineClickListener { onPolylineClick(it) }
        removeMarker.setOnClickListener {
            mMap.setOnMarkerClickListener { onMarkerClickRemove(it) }
        }
        removeAll.setOnClickListener { clearMap() }
    }

    private fun onMarkerClickRemove(p0: Marker?): Boolean {
        val num = markers.size - 1
        for (i in 0..num) {
            if ((p0?.position?.latitude == markers[i]?.latitude) && (p0?.position?.longitude == markers[i]?.longitude)) {
                markers[i] = null
                break
            }
        }
        for (i in num downTo 0) {
            if (markers[i] != null) {
                latestMarker = LatLng(markers[i]!!.latitude, markers[i]!!.longitude)
            }
        }
        p0?.remove()
        val marker: Marker? = null
        mMap.setOnMarkerClickListener {
            onMarkerClick(marker)
        }
        return true
    }

    override fun onMarkerClick(p0: Marker?): Boolean {

        polylineOptionsArray.add(
            PolylineOptions().add(latestMarker, p0!!.position).width(15f).color(Color.RED).clickable(true)
        )
        mMap.addPolyline(polylineOptionsArray.last())
        return true
    }



    override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
        super.onActivityResult(requestCode, resultCode, data)
        if (requestCode == REQUEST_CHECK_SETTINGS) {
            if (resultCode == Activity.RESULT_OK) {
                locationUpdateState = true
                startLocationUpdates()
            }
        }
        if (requestCode == AUTOCOMPLETE_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                val place:Place = Autocomplete . getPlaceFromIntent (data as Intent)
                Log.i("Search bar", "Place: " + place.getName() + ", " + place.getId())
            } else if (resultCode == AutocompleteActivity.RESULT_ERROR) {

// TODO: обработать ошибку.

                val status:Status = Autocomplete . getStatusFromIntent (data as Intent)
                Log.i("Search bar", status.getStatusMessage())
            } else if (resultCode == RESULT_CANCELED) {

// Пользователь отменил операцию

            }
        }
    }


    override fun onPause() {
        super.onPause()
        fusedLocationClient.removeLocationUpdates(locationCallback)
    }

    public override fun onResume() {
        super.onResume()
        if (!locationUpdateState) {
            startLocationUpdates()
        }
    }


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