Вызов API в mvvm Android

я новичок в mvvm, и я пытался вызвать API в kotlin в mvvm, используя модификацию. это мой xml

<TextView
        android:text="TextView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/textView" app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="84dp" app:layout_constraintTop_toTopOf="parent"/>
<Button
        android:text="Button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:id="@+id/button" app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintHorizontal_bias="0.498" app:layout_constraintEnd_toEndOf="parent"
        android:layout_marginTop="332dp" app:layout_constraintTop_toBottomOf="@+id/textView"
        android:layout_marginBottom="8dp" app:layout_constraintBottom_toBottomOf="parent"/>

вы можете видеть, что у меня есть только два элемента. одна кнопка для вызова API и вкл для показа кода результата вызова(будь то 200 или что-то другое).

class testViewModel: ViewModel() {
    var testInput :MutableLiveData<Int> = MutableLiveData(1)
    var test :LiveData<Int> = testInput
    fun clicked(){


        test = API_Repository.createCode()
        println(test.value.toString())

    }
}

это моя модель просмотра.

fun createCode(): LiveData<Int> {
    var sendUser = CreateCodeUserClass()
    sendUser.setUsername("09360767928")
    var data = MutableLiveData<Int>()
    my_API_Interface!!.CreateCode(sendUser).enqueue(object : retrofit2.Callback<Void> {
        override fun onFailure(call: Call<Void>, t: Throwable) {
            data.value = 10000
            println(data.value.toString())
        }

        override fun onResponse(call: Call<Void>, response: Response<Void>) {
            data.value = response.code()

        }

    })
    return data
}

и это мой вызов API

class MainActivity : AppCompatActivity() {

    public var viewModel = testViewModel()
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        viewModel = ViewModelProviders.of(this).get(testViewModel::class.java)
            viewModel.test!!.observe(this, Observer { data ->
                print(data.toString())
                textView.text = data.toString()
            })

        button.setOnClickListener {
            viewModel.clicked()
        }
    }
}

и это моя основная активность. когда я вызываю API в моем тесте модели просмотра, он всегда равен нулю, где он должен быть либо 10000, либо каким-либо другим числом. Я думаю, что функция createCode завершается до того, как сработает OnResponse или OnFailure. но я не знаю, что делать, и я хочу использовать mvvm.


person Dayyan Nili Sani    schedule 18.05.2019    source источник
comment
Вы пытались удалить println(test.value.toString()) в своем классе testViewModel, потому что ваш CreateCode(sendUser).enqueue является асинхронным вызовом, он всегда будет завершать функцию createCode до того, как будет запущен OnResponse или OnFailure   -  person tamtom    schedule 19.05.2019
comment
не думаю, что это что-то изменит. он просто показывает мне результат в журнале.   -  person Dayyan Nili Sani    schedule 21.05.2019
comment
@DayyanNiliSani Вы получили ответ..... Я тоже только что запустил mvvm и столкнулся с похожей проблемой.   -  person Shubham Anand    schedule 17.09.2019


Ответы (1)


Я предполагаю, что ваша проблема в том, что вы наблюдаете за активностью одного объекта LiveData, но когда вы получаете результат от API, вы просто заменяете этот объект новым LiveData. Вы должны дождаться результата и записать его в уже созданные LiveData в вашей ViewModel. Это возможно с MediatorLiveData. Что-то вроде этого:

val monthData = MediatorLiveData<MonthData>() /// livedata i subscribed in view

Это мой «вызов API» в модели представления. Вот главная магия. Я подписываю живые данные моей модели просмотра на результат моего «вызова API» и передаю данные оттуда в эти живые данные:

fun loadMonthEvents() {
    monthData.addSource(useCase.getCalendarEvents()) {
        monthData.value = it
    }
}

В моем случае мое репо на RxJava, и я конвертирую его в живые данные следующим образом (UseCase):

fun getCalendarEvents(): LiveData<MonthData?> {
    val result = mutableLiveDataOf<MonthData?>()

    appointmentsRepository.getAppointmentsIn().subscribe { data ->
        result.value = data
    }

    return result
}

Надеюсь, это поможет вам. В любом случае, просто прокомментируйте, если у вас все еще есть вопросы :)

person Sergey Grishin    schedule 22.06.2019
comment
Привет @Sergey Не могли бы вы объяснить? Я столкнулся с той же проблемой, получая null в ответ - person Jahanvi Kariya; 28.12.2020
comment
Привет, @JahanviKariya, будет здорово, если вы поделитесь своим кодом, потому что ваш случай может быть другим. Но если вы уверены, что это одно и то же, ок: в случае TS есть 2 LiveData - один создается в ViewModel при запуске, а другой - в методе репозитория (createCode). Итак, вы подпишетесь в пользовательском интерфейсе сначала на живые данные (из ViewModel), а затем вернете еще один из репозитория. Также вы не можете использовать живые данные сразу после их возврата (на следующей строке после createCode в случае TS), потому что вызов API является асинхронным, и данные не появятся сразу. - person Sergey Grishin; 29.12.2020