簡體   English   中英

ViewModel function 如何訪問 AutocompleteSupportFragment 的 PlaceSelectionListener 返回的 Place 實例?

[英]How can a ViewModel function access the Place instance returned by PlaceSelectionListener of AutocompleteSupportFragment?

我正在使用 Kotlin 構建一個 Android 應用程序。

我有一個包含create_button的布局。 當用戶單擊按鈕時, onClick應該在我的 ViewModel 中調用onCreateJourney() 此 function 需要selectedPlaceId參數來更新 Journey 實體的值。

在我的 Fragment 中,我使用 AutocompleteSupportFragment 讓用戶搜索並選擇所需的位置。 這很好用,因為onPlaceSelected()返回正確的位置以響應用戶的選擇。 但我無法弄清楚如何在我的 ViewModel onCreateJourney()

在這個階段,編譯器會拋出這個錯誤:

在 class 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)
    }
}

您必須將字段selectedPlaceId作為參數傳遞給 xml:

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

您將如何獲得視圖 model 中的 selectedPlaceId 取決於您的編程邏輯。

出於測試目的,您可以對值進行硬編碼。

在 NewJourneyViewModel 中,我將selectedPlaceId設置為 MutableLiveData。

val selectedPlaceId = MutableLiveData<String>()

在 NewJourneyFragment 中,我使用lateinit為 NewJourneyViewModel 創建了一個名為newJourneyViewModel的字段,並在onCreateView()中對其進行了初始化。

private lateinit var newJourneyViewModel : NewJourneyViewModel

現在可以在onCreateView()之外訪問我的 ViewModel,在我的 Fragment onPlaceSelected()方法中,我可以將selectedPlaceId的值設置為p0.id

newJourneyViewModel.selectedPlaceId.value = p0.id

如果有人能對此提出更好、更安全的方法,將不勝感激。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM