1

我试图创建一个包含国家列表的视图模型。View 模态类如下所示:

class Country_ViewModel(ctx:Context) :ViewModel(){

    val itemSelected : MutableLiveData<Int> by lazy{
        MutableLiveData<Int>()

    }
    val p = XmlPullParserHandler()
    private var count: MutableList<Country> = p.parse(openCountriesFile(ctx))
    val countryArray =MutableLiveData(count)

    
    // This function will open the XML file and return an input stream that  will be used by the Parse function
    fun openCountriesFile(context: Context): InputStream? {
        val assetManager: AssetManager = context.getAssets()
        var `in`: InputStream? = null
        try {
            `in` = assetManager.open("countries.xml")
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return `in`
    }



    // This function will loop thorough the country list and delete the entry that it got from the position
    fun removeItem(position: Int) {
        count.map { pos ->
            if (pos.compare(count[position]) == 0) {
                count.remove(pos)
                return
            }
        }
    }

函数 openCountriesFile 将只解析包含 Country 的 XML 文件并将其保存在 ModelView 内的 MutableLiveData 对象中。

稍后我想使用 Fragment 来观察更改的数据:此 Fragment 将使用我创建的 Adapter 并使用国家数据填充 Fragment。

该片段将如下所示:

class frag : Fragment(){

    val KEY_COUNTRY = "country"
    val KEY_NAME = "name"
    val KEY_FLAG = "flag"
    val KEY_ANTHEM = "anthem"
    val KEY_SHORT = "short"
    val KEY_DETAILS = "details"

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

    }
    val viewModal:Country_ViewModel by viewModels()

/*
* When creating the view we  would like to do the following:
* Initiate the Adapter.
* When the adapter has been called he will look for the XML file with the country's in it.
      Second one for the anthems
* */
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        val v = inflater.inflate(R.layout.fragment_frag, container, false)


        val rv = v.findViewById(R.id.rvTodos) as RecyclerView
        val adapter = countryAdapter(requireContext(),viewModal,this)
        viewModal.itemSelected.observe(viewLifecycleOwner, Observer<Int>{
            val fragment2 = details_frag()
            val fragmentManager: FragmentManager? = fragmentManager
            val fragmentTransaction: FragmentTransaction = fragmentManager!!.beginTransaction()

            fragmentTransaction.apply {
                replace(R.id.fragLand, fragment2)
                commit()
            }
        })
        rv.adapter = adapter



        // Apply the new content into the fragment layout
        val mLayoutManager = LinearLayoutManager(activity);
        rv.layoutManager = mLayoutManager
        return v
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {


    }


    override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater){
        super.onCreateOptionsMenu(menu, inflater)
        inflater.inflate(R.menu.primary_menu,menu)
    }




}

我会观察是否有一个国家被点击,如果有,我想移动到我的另一个片段以获取更多详细信息。

我的适配器看起来像这样:

class countryAdapter(
    var ctx: Context, var viewModal:Country_ViewModel, var owner: LifecycleOwner
) : RecyclerView.Adapter<countryAdapter.countryViewHolder>() {
//     lateinit var mListener: onItemLongClickListener
//    private lateinit var mSListener: onItemClickListener
    var player: MediaPlayer? =null
    private lateinit var count: MutableList<Country>





/**-----------------------------------INTERFACES --------------------------------------------------*/

//    interface onItemLongClickListener {
//
//        fun onItemLongClick(position: Int)
//    }
//
//    interface onItemClickListener {
//
//        fun onItemClick(position: Int): Boolean
//    }
/**-----------------------------LISTENERS --------------------------------------------------------*/

//    fun setOnItemLongClickListener(listener: onItemLongClickListener) {
//        mListener = listener
//
//    }
//    fun setOnItemClickListener(listener: onItemClickListener) {
//        mSListener = listener
//    }

/**-----------------------------INNER CLASS--------------------------------------------------------*/
    inner class countryViewHolder(itemView: View) :
        RecyclerView.ViewHolder(itemView) {
        val counrtyName = itemView.findViewById<TextView>(R.id.countryName)
        val populationNum = itemView.findViewById<TextView>(R.id.countryPopulation)
        val imageCount = itemView.findViewById<ImageView>(R.id.imageView)


/*
* Defining the listeners in the initialization of the Row in the  adapter
* */
        init {
        count= viewModal.countryArray.value!!
            itemView.setOnLongClickListener {
               viewModal.removeItem(adapterPosition)
                return@setOnLongClickListener true

            }
            itemView.setOnClickListener{
                viewModal.itemSelected.value=adapterPosition
                Log.i("Hello",adapterPosition.toString())
                startPlayer(adapterPosition,ctx)
            }

        viewModal.countryArray.observe(owner, Observer {
            notifyDataSetChanged()
        })
        }




    }
/**---------------------------------------VIEW HOLDER CREATE AND BIND ----------------------------- */
    /*
    * Will inflate the country XML file in the  adapter and then inflate it into the parent that is
    * the fragment.
    * At the end it will return the inner class with all the parameters that was initiated there.
    * */
    override fun onCreateViewHolder(
        parent: ViewGroup,
        viewType: Int
    ): countryAdapter.countryViewHolder {

        val view = LayoutInflater.from(parent.context).inflate(R.layout.itemcountry, parent, false)
        val context = parent.context
        val inflater = LayoutInflater.from(context)
        val contactView = inflater.inflate(R.layout.itemcountry, parent, false)

        return countryViewHolder(contactView)
    }

/*
* The function will be responsible to get the data that was initiated at the begining in the
* inner class and change the data that is displayed in the XML file to the new data  based on the
* Country that it got
* The position is parameter that is changing every time this function is called and adding all the
* Country that are in the XML into the  fragment
*
* */
    override fun onBindViewHolder(holder: countryViewHolder, position: Int) {

        var countryName1 = holder.counrtyName
        var countryPopulation1 = holder.populationNum
        var imagecount = holder.imageCount
        countryName1.setText(viewModal.countryArray.value?.get(position)?.name_of_country)
        countryPopulation1.setText(count?.get(position)?.shorty_of_country)
        count?.get(position)?.let {
        country_drawable.get(it.name_of_country)?.let {
            imagecount.setBackgroundResource(
                it
            )
        }
    }

    }

/**-----------------------------------------Functions ------------------------------------------- */
    fun startPlayer(position: Int,ctx:Context){
        player?.stop()
         player =
             count?.get(position)
                 ?.let { country_raw.get(it.name_of_country)?.let { MediaPlayer.create(ctx, it) } }
        player?.start()
    }





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


}

目标是如果用户单击 RecyclyView (OnClickListener) 中的一个国家/地区,那么我想移至第二个片段。

我有一个错误将创建 viewModal 实例,错误是:

无法创建 com.example.Country_ViewModel 类的实例

这是为什么?我初始化错了什么?

我应该在哪里创建 ViewModal 的实例?在适配器内部还是在片段本身内部?(可以将 viewModal 实例传递给适配器吗?或者还有另一种方法可以观察 CountryArray 的变化?)

谢谢你。

4

0 回答 0