导航到网络呼叫成功的另一个片段

时间:2020-07-06 13:15:58

标签: android kotlin retrofit2 kotlin-coroutines

我想按一个按钮从一个片段进行网络调用,如果网络调用成功,则要导航到另一个片段,如果不成功,则停留在当前片段中并在屏幕上显示错误。吐司。

我正在点击ReviewGameRulesFragment,从satrtGameButton进行网络呼叫,它看起来像这样:

    override fun onCreateView(
            inflater: LayoutInflater, container: ViewGroup?,
            savedInstanceState: Bundle?
        ): View? {
    
    viewModel = ViewModelProvider(requireActivity()).get(SetupGameViewModel::class.java)
    
    binding = DataBindingUtil.inflate<FragmentReviewGameRulesBinding>(
                inflater,
                R.layout.fragment_review_game_rules,
                container,
                false
            )
    
    binding.startGameButton.setOnClickListener {
                viewModel.createGame(this.view)
            }
}

createGame函数位于SetupGameViewModel文件中,如下所示:

fun createGame() {
        coroutineScope.launch {
            val createGameRequest = CreateGameRequest(
                gamePrice = gamePrice,
                gameRules = gameRules,
                playerOneGameName = playerOneGameName
            )
            var getPropertiesDeferred =
                ParagonApi.retrofitService.createGameAsync(createGameRequest)
            try {
                _createGameResponse.value = getPropertiesDeferred.await()
            } catch (e: Exception) {
            }
        }
    }

现在-我想在此呼叫成功时导航到另一个片段,或者在失败时停留在该片段。正确的方法是什么?

2 个答案:

答案 0 :(得分:0)

您可以使用LiveData观察状态,当状态为成功时,只需将其设置为已通知成功即可

为您的州创建课程

sealed class NetworkLoadingState {
    object OnLoading : NetworkLoadingState()
    object OnSuccess : NetworkLoadingState()
    data class OnError(val message: String) : NetworkLoadingState()
}

在您的SetupGameViewModel内创建一个LiveData实例进行观察

class SetupGameViewModel : ViewModel() {

   private var _loadState = MutableLiveData<Event<NetworkLoadingState>>()
    val loadState: LiveData<Event<NetworkLoadingState>>
        get() = _loadState

//Instead of `coroutineScope` use `viewModelScope`
fun createGame() {
       // coroutineScope.launch {
        viewModelScope.launch {
            
              _loadState.value = Event(NetworkLoadingState.OnLoading)
            
            val createGameRequest = CreateGameRequest(
                gamePrice = gamePrice,
                gameRules = gameRules,
                playerOneGameName = playerOneGameName
            )
            var getPropertiesDeferred =
                ParagonApi.retrofitService.createGameAsync(createGameRequest)
            try {
                _createGameResponse.value = getPropertiesDeferred.await()
              //Here is code
              _loadState.value = Event(NetworkLoadingState.OnSuccess)
            } catch (e: Exception) {
              _loadState.value = Event(NetworkLoadingState.OnError("Exception message here"))
            }
        }
    }


}

现在在您的片段中

 binding.startGameButton.setOnClickListener {
            viewModel.createGame(this.view)
            observeLoadingState()
        }

 private fun observeLoadingState() =
        viewModel.loadState.observe(viewLifecycleOwner, EventObserver {
            when (it) {
                is NetworkLoadingState.OnLoading -> println("You can show loading indicator here or whatever to inform user that data is being loaded")
                is NetworkLoadingState.OnSuccess -> println("Success now you can navigate")
                is NetworkLoadingState.OnError -> println(it.errorMessage)
            }
        })

这里是用于处理单个事件的Event类,否则当您的成功片段从后堆栈弹出时,您将导航回到成功屏幕

Event.kt

/*
 a* Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package your.package.name

import androidx.lifecycle.Observer

/**
 * Used as a wrapper for data that is exposed via a LiveData that represents an event.
 */
open class Event<out T>(private val content: T) {

    @Suppress("MemberVisibilityCanBePrivate")
    var hasBeenHandled = false
        private set // Allow external read but not write

    /**
     * Returns the content and prevents its use again.
     */
    fun getContentIfNotHandled(): T? {
        return if (hasBeenHandled) {
            null
        } else {
            hasBeenHandled = true
            content
        }
    }

    /**
     * Returns the content, even if it's already been handled.
     */
    //fun peekContent(): T = content
}

/**
 * An [Observer] for [Event]s, simplifying the pattern of checking if the [Event]'s content has
 * already been handled.
 *
 * [onEventUnhandledContent] is *only* called if the [Event]'s contents has not been handled.
 */
class EventObserver<T>(private val onEventUnhandledContent: (T) -> Unit) : Observer<Event<T>> {
    override fun onChanged(event: Event<T>?) {
        event?.getContentIfNotHandled()?.let {
            onEventUnhandledContent(it)
        }
    }
}

有关更多信息,您可以visit my repo,如果喜欢的话可以给星星。

答案 1 :(得分:0)

您应该在活动/片段中观察数据,如果它返回成功,则转到下一个屏幕。您可以使用liveData和mutableLiveData观察数据。