0

我正在使用 Kotlin 构建一个 Android 应用程序。

我有一个包含create_button的布局。当用户单击按钮时,onClick应该onCreateJourney()在我的 ViewModel 中调用。此函数需要selectedPlaceId参数来更新 Journey 实体的值。

在我的 Fragment 中,我使用 AutocompleteSupportFragment 让用户搜索并选择所需的位置。这很好用,因为onPlaceSelected()它会根据用户的选择返回正确的位置。但我不知道如何在我的 ViewModel 中使用返回的地点 id 值(p0.id)onCreateJourney()

在这个阶段,编译器会抛出这个错误:

在 com.example.traveljournal.journey.NewJourneyViewModel 类中找不到方法 onCreateJourney()

拜托,你能为我解释一下这个问题吗?

我的用户界面(.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"
    tools:context=".journey.NewJourneyFragment">

    <data>
        <variable
            name="newJourneyViewModel"
            type="com.example.traveljournal.journey.NewJourneyViewModel" />
    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/whereQuestion"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_marginTop="20dp"
            android:layout_marginEnd="10dp"
            android:text="@string/whereQuestion"
            android:textSize="18sp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintHorizontal_bias="0.027"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/journeyBckgImageView" />

        <androidx.cardview.widget.CardView
            android:id="@+id/cardView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:layout_constraintBottom_toBottomOf="parent">

        </androidx.cardview.widget.CardView>

        <fragment
            android:id="@+id/autocomplete_fragment"
            android:name="com.google.android.libraries.places.widget.AutocompleteSupportFragment"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="10dp"
            android:layout_marginTop="10dp"
            android:layout_marginEnd="10dp"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toBottomOf="@+id/whereQuestion" />

        <Button
            android:id="@+id/create_button"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginBottom="16dp"
            android:onClick="@{() -> newJourneyViewModel.onCreateJourney()}"
            android:text="@string/createJourneyButton"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />

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

我的视图模型

class NewJourneyViewModel (
        private val journeyKey: Long = 0L,
        val database: TravelDatabaseDao) : ViewModel() {

    private var viewModelJob = Job()

    private val uiScope = CoroutineScope(Dispatchers.Main + viewModelJob)

    private val _navigateToJourneys = MutableLiveData<Boolean?>()

    val navigateToJourneys: LiveData<Boolean?>
        get() = _navigateToJourneys

    fun doneNavigating() {
        _navigateToJourneys.value = null
    }

    fun onCreateJourney(selectedPlaceId: String) {
        uiScope.launch {
            withContext(Dispatchers.IO) {
                val journey = database.getJourney(journeyKey) ?: return@withContext
                journey.placeId = selectedPlaceId
                database.updateJourney(journey)
            }
            _navigateToJourneys.value = true
        }
    }

    override fun onCleared() {
        super.onCleared()
        viewModelJob.cancel()
    }
}

我的片段

class NewJourneyFragment : Fragment(), PlaceSelectionListener {

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        (activity as AppCompatActivity).supportActionBar?.title = getString(R.string.createJourney)

        val binding: FragmentNewJourneyBinding = DataBindingUtil.inflate(
            inflater,
            R.layout.fragment_new_journey, container, false
        )

        val application = requireNotNull(this.activity).application

        val arguments = NewJourneyFragmentArgs.fromBundle(arguments!!)

        val dataSource = TravelDatabase.getInstance(application).travelDatabaseDao

        val viewModelFactory = NewJourneyViewModelFactory(arguments.journeyKey, dataSource)

        val newJourneyViewModel =
            ViewModelProviders.of(
                this, viewModelFactory).get(NewJourneyViewModel::class.java)

        binding.newJourneyViewModel = newJourneyViewModel

        newJourneyViewModel.navigateToJourneys.observe(this, Observer {
            if(it == true) {
                this.findNavController().navigate(
                    NewJourneyFragmentDirections.actionNewJourneyDestinationToJourneysDestination())
                newJourneyViewModel.doneNavigating()
            }
        })

        if (!Places.isInitialized()) {
            this.context?.let { Places.initialize(it, getString(R.string.apiKey), Locale.US) }
        }

        val autocompleteFragment = childFragmentManager.findFragmentById(R.id.autocomplete_fragment)
                as? AutocompleteSupportFragment
        autocompleteFragment?.setOnPlaceSelectedListener(this)
        autocompleteFragment!!.setHint(getString(R.string.destinationExample))
        autocompleteFragment!!.setPlaceFields(Arrays.asList(Place.Field.ID, Place.Field.NAME))

        return binding.root
    }

    @ExperimentalStdlibApi
    override fun onPlaceSelected(p0: Place) {
        Log.i("PLACE", "Place: " + p0.name + ", " + p0.id)
    }

    override fun onError(status: Status) {
        Toast.makeText(this.context,""+status.toString(),Toast.LENGTH_LONG).show()
        Log.i("ERROR", "An error occurred: " + status)
    }
}
4

2 回答 2

0

在 NewJourneyViewModel 中,我设置selectedPlaceId为 MutableLiveData。

val selectedPlaceId = MutableLiveData<String>()

在 NewJourneyFragment 中,我曾经lateinit为 NewJourneyViewModel 创建一个字段,newJourneyViewModel并在onCreateView().

private lateinit var newJourneyViewModel : NewJourneyViewModel

现在可以访问我的 ViewModel 之外onCreateView(),在我的 Fragment onPlaceSelected()方法中,我可以将值设置selectedPlaceIdp0.id

newJourneyViewModel.selectedPlaceId.value = p0.id

如果有人能对此提出更好、更安全的方法,将不胜感激。

于 2020-04-05T09:55:06.123 回答
0

您必须将该字段selectedPlaceId作为 xml 中的参数传递:

android:onClick="@{() -> newJourneyViewModel.onCreateJourney(newJourneyViewModel.selectedPlaceId)}"

您将如何在视图模型中获取 selectedPlaceId 取决于您的编程逻辑。

出于测试目的,您可以对值进行硬编码。

于 2020-04-04T20:16:39.697 回答