Возможно ли получить `RecyclerView` из фрагмента?

Пытаясь получить RecyclerView из этого макета:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".listFragment">

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/recyclee">
</android.support.v7.widget.RecyclerView>

в основной класс деятельности:

    private var mBlogList = findViewById<RecyclerView>(R.id.recyclee)

получить ошибку:java.lang.NullPointerException: Attempt to invoke virtual method 'android.view.Window$Callback android.view.Window.getCallback()' on a null object referenceлюбая помощь, пожалуйста:)

редактировать 1

сейчас я использую расширение kotlin

import kotlinx.android.synthetic.main.fragment_list.*
class MainActivity : AppCompatActivity() {
private lateinit var mBlogList : RecyclerView

в методе onCreate:

        mBlogList = recyclee

но та же ошибка все еще существует

редактировать 2 listFragment код:

class listFragment : Fragment() {

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

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    recyclee != null
}
companion object {
    fun newInstance(): listFragment = listFragment()
}
}

отредактируйте 3 всего кода MainActivity:

//this app supposed to read from FirebaseDatabase
//into Recycler view
//the RecyclerView is into Fragment layout
//i use Fragments into FrameLayout in the activity_main.xml
// the RecyclerView should be shown when navigatoinBar is clicked
//or on start of MainActivity
class MainActivity : AppCompatActivity() {
    private var mDatabase:DatabaseReference? = null
    private lateinit var mBlogList : RecyclerView
    private var query:Query?=null
    private var options:FirebaseRecyclerOptions<Blog>?=null
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        //start listFragment , RecyclerView is there
        val mFragment = listFragment.newInstance()
        //openFragment method is below
        openFragment(mFragment)
        //navigation bottom onclicklistener


navBar.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
        //get data from database
        mDatabase=FirebaseDatabase.getInstance().getReference().child("mall")
        mDatabase?.keepSynced(true)
        //here i should have recyclee but it is null i don't know why
        mBlogList = recyclee
        mBlogList.setHasFixedSize(true)
        mBlogList.layoutManager = LinearLayoutManager(this)
        //query of database
        query = mDatabase?.orderByKey()

    }
private val mOnNavigationItemSelectedListener = BottomNavigationView.OnNavigationItemSelectedListener { item ->
   //there are 4 icons in the navigation_bottom_bar 
    //now we are talking about listNav icon only because it is realted 
    // with listFragment
    when (item.itemId) {
        R.id.listNav -> {
            val mFragment = listFragment.newInstance()
            openFragment(mFragment)
            return@OnNavigationItemSelectedListener true
        }
        R.id.cartNav -> {
            val mFragment = cartFragment.newInstance()
            openFragment(mFragment)
            return@OnNavigationItemSelectedListener true
        }
        R.id.supportNav -> {
            val mFragment = supportFragment.newInstance()
            openFragment(mFragment)
            return@OnNavigationItemSelectedListener true
        }
        R.id.accountNav -> {
            val mFragment = accountFragment.newInstance()
            openFragment(mFragment)
            return@OnNavigationItemSelectedListener true
        }
    }
    false
}
private fun openFragment(fragment: Fragment) {
    //open Fragment into FrameLayout in the main_activity.xml
    val transaction = supportFragmentManager.beginTransaction()
    transaction.replace(R.id.mainFrame, fragment)
    transaction.addToBackStack(null)
    transaction.commit()
}

override fun onStart() {
    super.onStart()
    //set options for FirebaseRecyclerAdapter
    options = FirebaseRecyclerOptions.Builder<Blog>()
            .setQuery(query!!, Blog::class.java)
            .build()
    //set custom adapter
    val mAdapter = object : FirebaseRecyclerAdapter<Blog, BlogViewHolder>(
            options!!) {
        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): BlogViewHolder {
            val view = LayoutInflater.from(parent.context)
                    .inflate(R.layout.cardview, parent, false)
            return BlogViewHolder(view)}

        override fun onBindViewHolder(holder: BlogViewHolder, position: Int, model: Blog) {
            holder.setTitle(model.title)
            holder.setDes(model.des)
            holder.setImage(applicationContext, model.image)
        }
    }
    mBlogList.adapter = mAdapter
}
inner class BlogViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
    var mView:View= itemView
    //set title, des amd image with data we got from database
    fun setTitle(title:String){
        var postTitle = mView.findViewById<TextView>(R.id.post_title)
        postTitle?.text = title
    }
    fun setDes(des:String){
        var postDes = mView.findViewById<TextView>(R.id.post_des)
        postDes?.text = des
    }
    fun setImage(image:String){
        var postImage = mView.findViewById<ImageView>(R.id.post_title)
        Picasso.get().load(image).into(postImage)
    }
}

}

4 ответа

Решение

Если вы подаете заявку kotlin-android-extensions плагин, то вам не нужно использовать findViewById больше, потому что вы можете получить доступ к представлениям в макете, как если бы они были свойствами (по имени). Так что ваши onCreate может выглядеть следующим образом:

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)

    assert recyclee != null
}

редактировать

Так как вы пытаетесь сделать это в Fragment и ваш файл макета называется fragment_List.xml тогда в вашем Fragment сначала вы должны надуть макет, а затем вы можете получить доступ к RecyclerView как в примере выше для Activity:

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

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

    assert recyclee != null
}

Если вы попытаетесь получить доступ к вашему RecyclerView в Activity до fragment_List раздувается в Fragment тогда это будет очевидно null (он еще не был создан). Это на самом деле то, что вы пытаетесь сделать в onCreate - слишком рано Fragment's макет еще не построен.

Редактировать 2

Как видно из вашего кода, mBlogList = recyclee установлен в onCreate, Хотя это сделано после ListFragment еще слишком рано onCreateView еще не был вызван, и поэтому нет макета на месте.

Быстрое решение было бы сделать это в onStart как в тот момент ListFragment определенно там. Тем не менее, лучший подход заключается в том, чтобы сделать логику внутри ListFragment сам и общаюсь с MainActivity через обратные вызовы, как описано здесь

Попробуйте использовать findViewById onCreate или OnCreateView (если вы во фрагменте). Это происходит потому, что до этого методы ваш макет еще не был раздут, поэтому Android не может найти ваш RecyclerView

class MainActivity : AppCompatActivity() {

     private lateinit var mBlogList : RecyclerView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        mBlogList = findViewById<RecyclerView>(R.id.recyclee)
    }
}

Я бы порекомендовал вам прочитать это: https://kotlinlang.org/docs/tutorials/android-plugin.html Kotlin есть лучший способ получить ссылку на ваши взгляды, вам не нужно использовать findViewById знак равно

Вы не можете позвонить findViewById из глобальной сферы. Но вы можете объявить это как:

private val mBlogList by lazy { findViewById<RecyclerView>(R.id.recyclee) }

... тогда используйте переменную как обычно.

Таким образом, вы могли получить доступ RecyclerViewатрибуты после загрузки адаптера в onCreate()функция

      var recyclerView : RecyclerViewAdapterYourClass = adapter as RecyclerViewAdapterYourClass 
       
recyclerView.yourRecyclerAttribute
Другие вопросы по тегам