是否可以从Fragment获取“ RecyclerView”?

时间:2018-08-15 13:03:09

标签: android android-recyclerview kotlin android-framelayout

尝试从此布局中获取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)
    }
}

}

3 个答案:

答案 0 :(得分:1)

如果您应用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本身的逻辑,并通过here

所述的回调与MainActivity进行通信

答案 1 :(得分:0)

尝试在onCreate或onCreateView上使用findViewById(如果您在Fragment中)。之所以发生这种情况,是因为在使用这种方法之前,您的布局尚未膨胀,因此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 =)

答案 2 :(得分:0)

您不能从全局范围调用findViewById。但是,您可以将其声明为:

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

...然后通常使用该变量。