Как заставить фрагмент ждать до текущего местоположения в Android Kotlin - PullRequest
0 голосов
/ 18 октября 2019

Я хочу, чтобы фрагмент ожидал текущего местоположения пользователя, а затем создал viewModel, который получает внутри блока init список данных в соответствии с координатами, которые были переданы в конструктор viewModel.

Я пыталсячтобы решить эту проблему, написав сопрограмму, но это еще не удалось. Модель viewModel создается перед получением местоположения.

OverviewFragment.kt

class OverviewFragment: Fragment() {


   private var searchOptions: SearchOptions? = null
   private var radiusCenterPointLocation: Location? = null
   private val job = Job()
   private val coroutineScope = CoroutineScope(Dispatchers.Main + job)

   override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
       savedInstanceState: Bundle?): View? {

       val binding: FragmentOverviewBinding = DataBindingUtil.inflate(inflater, R.layout.fragment_overview, container, false)

       binding.lifecycleOwner = this

       try {
           searchOptions = OverviewFragmentArgs.fromBundle(arguments!!).searchOptions
       } catch (e: Exception) {
       }

       if (radiusCenterPointLocation == null ) {
           coroutineScope.launch {
               radiusCenterPointLocation =
                   async{ getCurrentLocation()}.await()
           }
       }

       Log.i("onCreateView", "We got location")

       val viewModelFactory = OverviewViewModelFactory(searchOptions, radiusCenterPointLocation)

       val viewModel = ViewModelProviders.of(this,
           viewModelFactory).get(OverviewViewModel::class.java)

       binding.viewModel = viewModel

И функция getCurrentLocation ()

suspend fun getCurrentLocation(): Location? {
        val fusedLocationProviderClient = LocationServices.getFusedLocationProviderClient(context!!)
        return withContext(Dispatchers.Main) {
            val task = fusedLocationProviderClient.lastLocation
            while (!task.isSuccessful) {
                delay(1000)
            }
            Log.i("return location", "${task.result!!.latitude}")
            return@withContext task.result
        }
    }

Вот что показывает журнал в отношении местоположения:

2019-10-18 11:31:49.095 11304-11304/com.package I/onCreateView: We got location
2019-10-18 11:31:51.291 11304-11304/com.package I/return location: 44.4255631

Таким образом, в соответствии с журналами, местоположение возвращается после того, как это необходимо для создания viewModel. Как я могу заставить код «ждать» результата функции getCurrentLocation ()?

1 Ответ

1 голос
/ 18 октября 2019

Поток пользовательского интерфейса не должен ждать ничего. Я имею в виду, что если на пользовательском интерфейсе еще нет места, доступного для отображения индикатора прогресса, или что-то в этом роде.

Кроме того, идея MVVM (поэтому архитектура, представляющая ViewModels) заключается в том, что представление реагирует на состояние, и обавид независимый. Итак, ваш фрагмент не должен требовать определения местоположения, он должен только наблюдать, как живые данные связываются с этим местоположением.

Итак, я бы предложил следующее:

Model:

class LocationModel {
    val locationData: MutableLiveData<Location> = MutableLiveData()

    init {
        getLocation()
    }

    fun getLocation() {
        ...
        locationData.set(position)
    }

    fun getLocationData(): LiveData<Location> { return locationData }
}

ViewModel:
// just "proxy" between Fragment, LocationModel and others Model

Fragment: 
class Fragment: Fragment() {
    fun onViewCreated() {
        viewModel.getLocationData().observe(viewLifecycleOwner) { location -> 
            if (location == null) {
                showProgress()
            } else {
                showLocation()
            }
        }
    }
}

Я знаю здесь о сопрограммах и другихвещи, потому что ваша основная проблема заключается в том, что вы хотите заблокировать поток пользовательского интерфейса до завершения потенциально блокирующей операции. Это закончится с ANR.

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