ViewModel onChanged获取无限循环

时间:2019-08-09 17:28:22

标签: android kotlin mvvm data-binding android-livedata

我尝试使用mvvm +数据绑定+ livedata进行练习 但陷入无限循环。 请告诉我如何解决它,谢谢!

这是我的代码:

layout.xml

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <data>
        <variable
            name="viewModel"
            type="com.guanhong.mvvmpractice.viewmodel.MainViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".view.MainActivity">

        <TextView
            android:id="@+id/name"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dp"
            android:gravity="center"
            android:onClick="onViewClick"
            android:text="@{@string/player_name(viewModel.dataItem.firstName, viewModel.dataItem.lastName)}"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toTopOf="parent" />

        <TextView
            android:id="@+id/heightFeet"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginTop="50dp"
            android:gravity="center"
            android:onClick="onViewClick"
            android:text="@{@string/high_feet(viewModel.dataItem.heightFeet.toString())}"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/name" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

MainActivity

class MainActivity : AppCompatActivity() {

    lateinit var binding: ActivityMainBinding
    lateinit var viewModel: MainViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = DataBindingUtil.setContentView(this, R.layout.activity_main)
        binding.lifecycleOwner = this

        viewModel = ViewModelProviders.of(this).get(MainViewModel::class.java)
        binding.viewModel = viewModel

        viewModel.dataItem.observe(this,
            Observer<DataItem> { dataItem ->

                Log.d("Huang", " MainActivity Observer " + dataItem.firstName)

                viewModel.dataItem.value = dataItem
            })

        viewModel.init()
    }
}

存储库

class MainRepository {

    fun getAllPlayer(callback: GetAllPlayerCallback) {

        val retrofit = Retrofit
            .Builder()
            .addConverterFactory(GsonConverterFactory.create())
            .baseUrl("https://free-nba.p.rapidapi.com/")
            .build()

        val allPlayerData = retrofit.create(AllPlayerApi::class.java)

        val call = allPlayerData.getAllPlayer(2)

        call.enqueue(object : Callback<AllPlayerData> {
            override fun onFailure(call: Call<AllPlayerData>?, t: Throwable?) {
                Log.d("Huang", " MainRepository get player fail ")
            }

            override fun onResponse(call: Call<AllPlayerData>?, response: Response<AllPlayerData>) {

                Log.d("Huang", " MainRepository onResponse ")

                callback.onSuccess(response.body()!!.data!!)
            }
        })
    }
}

ViewModel

class MainViewModel : ViewModel() {

    private val repository = MainRepository()

    var dataItem = MutableLiveData<DataItem>()

    fun init() {
        getAllPlayer()
    }

    private fun getAllPlayer() {

        repository.getAllPlayer(object : GetAllPlayerCallback {
            override fun onSuccess(dataItemList: List<DataItem>) {

                Log.d("Huang", " MainViewModel getAllPlayer onSuccess ")

                dataItem.value = (dataItemList[0])
            }
        })
    }
}

Logcat

logcat

3 个答案:

答案 0 :(得分:0)

由于在观察者函数内部,该函数观察ViewModel中的实时数据,因此您可以立即设置新值来更新所有观察者。这是无限循环。您不应从视图更新实时数据变量。视图(片段,活动)应仅观察数据。

viewModel.dataItem.observe(this,
            Observer<DataItem> { dataItem ->

                Log.d("Huang", " MainActivity Observer " + dataItem.firstName)

                // Problem is below
                // viewModel.dataItem.value = dataItem
            })

答案 1 :(得分:0)

您正在更新其回调中的观察者数据,因此只要调用 viewModel.dataItem.value = dataItem 它给您回调并陷入无限循环

viewModel.dataItem.observe(this,
            Observer<DataItem> { dataItem ->

                Log.d("Huang", " MainActivity Observer " + dataItem.firstName)

                viewModel.dataItem.value = dataItem
            })viewModel.dataItem.observe(this,
            Observer<DataItem> { dataItem ->

                Log.d("Huang", " MainActivity Observer " + dataItem.firstName)

                viewModel.dataItem.value = dataItem
            })

答案 2 :(得分:0)

我还遇到了使用 ViewModel Databinding 库时遇到的问题。我通过以下方法解决了这个问题。

class SplashViewModel @Inject constructor(private val apiRepository: ApiRepository) : ViewModel() {

    private val _isLogin = MutableLiveData<LoginResultData>()
    val isLogin: LiveData<LoginResultData> = _isLogin

    fun login(mobile:String){
        viewModelScope.launch(networkExceptionHandler) {
            var login = apiRepository.login(mobile)
            _isLogin.value = login
            showLog("login : "+login)
        }
    }

}

实际上,当发出新值时,您需要设置该值,而忽略之前的值(如果保持不变)。