Android Kotlin. Проблемы с привязкой данных к представлению переработчика с использованием фрагментов - PullRequest
0 голосов
/ 18 ноября 2018

Я пытаюсь узнать, как реализовать привязку данных в приложении Android.У меня есть небольшое приложение, с которым я работаю, чтобы узнать это.И пока у меня есть привязка данных, работающая для части приложения.Я столкнулся с ошибкой, пытаясь реализовать программу повторного просмотра.Я просто не могу этого понять.Били по нему два-три дня и расстраивались.Думаю, я бы попросил вас, ребята.

Приложение на данный момент очень простое.

Часть, на которой я застрял, - это доступ к моему обзору реселлера из макета .xml с моего MainFragment.kt

Сначала я пытался использовать связывание, но был разочарован и вернулся к простой попытке использовать findViewById, но это также вызывает у меня проблему.Я начинаю думать, что у меня нет такого твердого понимания привязки данных, как я думал.

Это фрагмент, который содержит recyclerView:

фрагмент_основа.xml

<androidx.recyclerview.widget.RecyclerView
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:layout_marginTop="8dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            android:layout_marginStart="8dp"
            android:layout_marginBottom="8dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            android:layout_marginEnd="8dp"
            android:id="@+id/job_recyclerView"/>

У меня есть еще один небольшой файл макета, который использует Cardview для отображения каждого отдельного элемента в обзоре переработчика

Супер простая модель:

JobData.kt

data class JobData(val companyName: String, val location: String)

Адаптер:

JobAdapter.kt

class CustomAdapter(val userList: ArrayList<JobData>) : RecyclerView.Adapter<CustomAdapter.ViewHolder>() {

//Returning view for each item in the list
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): CustomAdapter.ViewHolder {
    val v = LayoutInflater.from(parent.context).inflate(R.layout.job_item_layout, parent, false)
    return ViewHolder(v)
}

//Binding the data on the list
override fun onBindViewHolder(holder: CustomAdapter.ViewHolder, position: Int) {
    holder.bindItems(userList[position])
}

override fun getItemCount(): Int {
    return userList.size
}

//Class holds the job list view
class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {

    fun bindItems(job: JobData) {
        val textViewName = itemView.findViewById(R.id.tv_company_name) as TextView
        val textViewAddress  = itemView.findViewById(R.id.tv_Location) as TextView
        textViewName.text = job.companyName
        textViewAddress.text = job.location
    }
}
}

А затем код в моем главном фрагментесправиться со всем этим, чего он не делает.Я попробовал все, это становилось ужасно.Как вы можете видеть ниже.Привязка на месте и работает для моего FloatingActionButton.Но я по какой-то причине не могу понять, как получить доступ к этому recylerview.В тот момент, когда код приведен ниже, я подумал, что просто хочу получить доступ с помощью findViewById, но это тоже не работает.

MainFragment.kt class MainFragment: Fragment () {

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
    val binding: FragmentMainBinding = DataBindingUtil.inflate(
        inflater, R.layout.fragment_main, container, false)

    //Setting onClickListener for FAB(floating action button) using Navigation
    binding.createNewJobFAB.setOnClickListener { v: View ->
        v.findNavController().navigate(R.id.action_mainFragment_to_createNewJobFragment)
    }

    //getting recyclerview from xml
    val recyclerView = findViewById(R.id.job_recyclerView) as RecyclerView

    //adding a layoutmanager
    recyclerView.layoutManager = LinearLayoutManager(this, RecyclerView.VERTICAL, false)


    //Arraylist to store jobs using the data class JobData
    val jobs = ArrayList<JobData>()

    //add dummy data to list
    jobs.add(JobData("A Company", "Town A"))
    jobs.add(JobData("B Company", "Town B"))
    jobs.add(JobData("C Company", "Town C"))
    jobs.add(JobData("D Company", "Town D"))

    //creating adapter
    val adapter = CustomAdapter(jobs)

    //add adapter to recyclerView
    recyclerView.adapter = adapter
    return binding.root
}
}

Выше не удается скомпилировать по двум причинам:

  1. findViewById отображается как «неразрешенная ссылка».
  2. При добавлении layoutManager «this» отображается как«Несоответствие типов»

Я полагаю, это связано с тем, что фрагменты не имеют контекста.Во всяком случае, я так думаю.Но я не знаю, чтобы решить это?Может быть, переопределить какой-то другой метод, но я не могу понять, какой и как?

О, и MainActivity выглядит так:

MainActivity.kt

class MainActivity : AppCompatActivity() {

//private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    @Suppress("UNUSED_VARIABLE")
    val binding = DataBindingUtil.setContentView<ActivityMainBinding>(this, R.layout.activity_main)
}

//Ensures back button works as it should
override fun onSupportNavigateUp() = findNavController(this, R.id.navHostFragment).navigateUp()
}

Который указывает на Nav_Graph для Android-навигации (часть JetPack).Этот бит в порядке и работает.

Добавление файлов Gradle, чтобы показать, что мои зависимости были установлены правильно, как предложено ниже.

app / gradle

android {
compileSdkVersion 28
dataBinding {
    enabled = true
}
...
}

kapt {
generateStubs = true
correctErrorTypes = true
}

dependencies {
...
kapt "com.android.databinding:compiler:$gradle_version"

...
}

Ответы [ 3 ]

0 голосов
/ 18 ноября 2018

Хорошо, поэтому в первую очередь вы получаете ошибку на findViewById, потому что ваш фрагмент не знает о представлении, которое содержит recyclerView

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

var rootView

// Inside onCreateView
var rootView = inflater?.inflate(R.layout.fragment, container, false) 

Теперь замените, findViewById() на rootView.findViewById()

И другая ошибкапоскольку фрагмент не имеет собственного контекста, замените this на activity!!

. Написав activity!!, вы вызываете метод getActicity(), который возвращает контекст родительской активности.

0 голосов
/ 18 ноября 2018

Включите ваш xml в <layout>..<layout/>

private lateinit var binding: FragmentXXXBinding

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
        binding = FragmentXXXBinding.inflate(inflater)
        return binding.root
    }

Затем вы можете вызвать recyclerview по binding.jobRecyclerview

, попытаться установить все прослушиватели кликов и т. Д. На onViewCreated, а не onCreateView фрагмента

0 голосов
/ 18 ноября 2018

Это неправильный способ найти ViewById из фрагмента (это хорошая техника для Activity):

val recyclerView = findViewById(R.id.job_recyclerView) as RecyclerView

Сначала макет фрагмента должен возвращаться методом onCreateView ().

override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
  return inflater.inflate(R.layout.fragment_main, container, false)
}

Мне лично нравится делать всю бизнес-логику фрагмента внутри onViewCreated ()

override fun onViewCreated(view: View?, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    //Now, we can use views by kotlinx
    //val recyclerView = job_recyclerView
    //Or old-fashioned way
    val recyclerView = getView()!!.findViewById(R.id.job_recyclerView) as RecyclerView
}

Доступ к RecylerView из макета фрагмента можно получить, имея корневой вид, например: getView()!!.findViewById или kotlinx внутри onViewCreated (): job_recyclerView

...