片段未附加到上下文

Posted

技术标签:

【中文标题】片段未附加到上下文【英文标题】:Fragment is not attached to a context 【发布时间】:2021-09-28 04:34:56 【问题描述】:

我打算在一个名为“FazendaListFragment”的片段中显示先前在数据库 (SQLite) 中注册的农场 (Fazendas) 列表,该片段是 FazendaActivity 的一部分。在这里,我有两个屏幕使用 ViewPage 通过滑动进行屏幕更改,但是我在这个问题的标题中报告了这个问题。我不知道如何通过附加上下文解决这个问题。下面是代码:

FazendaActivity

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

    setupTabs()


private fun setupTabs()
    val adapter = ViewPagerAdapter(supportFragmentManager)
    adapter.addFragment(FazendaListFragment(), "")
    adapter.addFragment(ListaPastoFragment(), "")

    view_pager_fazenda.adapter = adapter
    tabs.setupWithViewPager(view_pager_fazenda)

    tabs.getTabAt(0)!!.setIcon(R.drawable.ic_baseline_foundation_24)
    tabs.getTabAt(1)!!.setIcon(R.drawable.ic_outline_fence_24)

FazendaListFragment (已更新)

ar nameList = ArrayList<String>()

//Iniciando RecyclerView
var fazendaAdapter: FazendaListAdapter? = null
var linearLayoutManager: LinearLayoutManager? = null

//Iniciando o SQLite
var fazendaList = ArrayList<Fazenda>()
val fazendaDatabaseHandler by lazy  FazendaDatabaseHandler(requireContext()) 

private var cadastroFazenda: FloatingActionButton? = null

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? 
    // Inflate the layout for this fragment
    return inflater.inflate(R.layout.fragment_lista_fazenda, container, false)


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


private fun deleteAdapter(position: Int)
    fazendaList.removeAt(position)
    fazendaAdapter!!.notifyItemRemoved(position)


private fun initView() 
    fazendaList = fazendaDatabaseHandler.fazendas()
    fazendaAdapter = FazendaListAdapter(fazendaList, requireContext(), this::deleteAdapter)
    linearLayoutManager = LinearLayoutManager(context)
    recyclerview.layoutManager = linearLayoutManager
    recyclerview.adapter = fazendaAdapter

FazendaListAdapter

internal var fazendaList: List<Fazenda> = ArrayList<Fazenda>()
init
    this.fazendaList = fazendaList


//Aqui é onde o ViewHolder é criado a partir do layout
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder 
    val view = LayoutInflater.from(context).inflate(R.layout.content_fazenda_list, parent, true)
    return ViewHolder(view)


//Nessa parte é onde se modifica o item do ViewHolder
override fun onBindViewHolder(holder: ViewHolder, position: Int) 
    val fazenda = fazendaList[position]

    holder.name.text = fazenda.nome
    holder.cnpj.text = fazenda.cnpj
    holder.endereco.text = fazenda.endereco

    holder.editbtn.setOnClickListener
        val intent = Intent(context, CadastroFazendaActivity::class.java)
        intent.putExtra("edit", true)
        intent.putExtra("position", fazenda.id)
        context.startActivity(intent)
    
    holder.delbtn.setOnClickListener
        val view = View.inflate(context, R.layout.dialog_confirm_delete_fazenda, null)

        val builder = AlertDialog.Builder(context)
        builder.setView(view)

        val dialog = builder.create()
        dialog.show()
        dialog.window?.setBackgroundDrawableResource(android.R.color.transparent)

        view.btn_delete.setOnClickListener 
            val fazendaDatabaseHandler = FazendaDatabaseHandler(context)
            fazendaDatabaseHandler.deleteFazenda(fazenda.id)
            callbacks(position)
            dialog.dismiss()
        
    


//Devolve a quantidade de itens do fazendaList
override fun getItemCount(): Int 
    return fazendaList.size


//Aqui é a criação dos itens do ViewHolder
inner class ViewHolder(view: View): RecyclerView.ViewHolder(view)
    var name: TextView = view.tvAdpNome
    var cnpj: TextView = view.tvAdpCNPJ
    var endereco: TextView = view.tvAdpEndereco
    var delbtn: Button = view.deleteButton
    var editbtn: Button = view.editButton

ViewPagerAdapter

private val mFragmentList = ArrayList<Fragment>()
private val mFragmentTitleList = ArrayList<String>()

override fun getItem(position: Int): Fragment 
    return mFragmentList[position]


override fun getCount(): Int 
    return mFragmentList.size


override fun getPageTitle(position: Int): CharSequence? 
    return mFragmentTitleList[position]


fun addFragment(fragment: Fragment, title: String)
    mFragmentList.add(fragment)
    mFragmentTitleList.add(title)

错误日志在这里:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: br.com.appintellipec, PID: 6685
java.lang.RuntimeException: Unable to start activity ComponentInfobr.com.appintellipec/br.com.appintellipec.FazendaActivity: java.lang.IllegalStateException: Fragment FazendaListFragment524ae27 (f65a2c7c-2524-45f7-908a-12db24890acc) not attached to a context.
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3449)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:223)
    at android.app.ActivityThread.main(ActivityThread.java:7656)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
 Caused by: java.lang.IllegalStateException: Fragment FazendaListFragment524ae27 (f65a2c7c-2524-45f7-908a-12db24890acc) not attached to a context.
    at androidx.fragment.app.Fragment.requireContext(Fragment.java:900)
    at br.com.appintellipec.fragments.FazendaListFragment.<init>(FazendaListFragment.kt:32)
    at br.com.appintellipec.FazendaActivity.setupTabs(FazendaActivity.kt:22)
    at br.com.appintellipec.FazendaActivity.onCreate(FazendaActivity.kt:17)
    at android.app.Activity.performCreate(Activity.java:8000)
    at android.app.Activity.performCreate(Activity.java:7984)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1309)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3422)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3601) 
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:85) 
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) 
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) 
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
    at android.os.Handler.dispatchMessage(Handler.java:106) 
    at android.os.Looper.loop(Looper.java:223) 
    at android.app.ActivityThread.main(ActivityThread.java:7656) 
    at java.lang.reflect.Method.invoke(Native Method) 
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947) 

【问题讨论】:

是应用程序甚至没有编译还是运行时错误,您的问题到底是什么,添加一些Logs 以帮助我们更好地理解 我添加了日志。是一个致命的例外。当它到达这个片段时它会崩溃。 【参考方案1】:

您不能在属性初始化站点调用requireContext(),因为属性在 Fragment 实例仍在构造期间进行初始化,此时它可能会附加到上下文。这一行有你的错误:

var fazendaDatabaseHandler = FazendaDatabaseHandler(requireContext())

您可以延迟加载它,因此它只会在您第一次使用该属性时调用requireContext()

val fazendaDatabaseHandler by lazy  FazendaDatabaseHandler(requireContext()) 

或者您可以将其设为lateinit var 并在onViewCreated() 中对其进行初始化,此时可以安全地调用requireContext()

lateinit var fazendaDatabaseHandler: FazendaDatabaseHandler

override fun onViewCreated(view: View, savedInstanceState: Bundle?) 
    fazendaDatabaseHandler = FazendaDatabaseHandler(requireContext())
    //...

【讨论】:

谢谢。显然这个问题已经解决了。但现在我们有这个日志: java.lang.NullPointerException: Attempt to invoke virtual method 'void androidx.recyclerview.widget.RecyclerView.setLayoutManager(androidx.recyclerview.widget.RecyclerView$LayoutManager)' on an null object reference 共享的代码不足,无法准确查看问题所在。我没有看到您的 recyclerView 财产声明。在onCreateView() 函数中调用initView() after return 或在onResume() 中重复调用它是没有意义的。任何视图设置都应在onViewCreated() 中完成。 如果您正在使用合成视图引用,那么它已被弃用,因为它会导致 NullPointerExceptions,除非您确切地知道您正在对视图初始化、设置和片段生命周期做什么。您应该迁移到视图绑定。 我已经更新了问题中的 FazendaListFragment 代码。我使用“import kotlinx.android.synthetic.main.activity_fazendas_list.*”直接获取布局的这个 recyclerview。 我建议您阅读这些文章并迁移到视图绑定。 android-developers.googleblog.com/2020/11/…developer.android.com/topic/libraries/view-binding/migration【参考方案2】:

您应该只为方法initView() 初始化一次。它是onCreateViewonResume

接下来,您应该使用requiredContext() 而不是context

fazendaAdapter = FazendaListAdapter(fazendaList, requiredContext(), this::deleteAdapter)

更新:

看起来您没有为视图实现。所有视图都应返回到 onCreateView 中。看来你早点退货了。

override fun onCreateView(
    inflater: LayoutInflater, container: ViewGroup?,
    savedInstanceState: Bundle?
): View? 
    // Inflate the layout for this fragment
    val view = inflater.inflate(R.layout.fragment_lista_fazenda, container, false)
    initView()
    return view //This one need at the last


override fun onResume() 
    super.onResume()
    //initView() //comment this one. you just need to implement one only

【讨论】:

我这样做了,但我遇到了同样的错误。我在问题中添加了日志。 你在哪里初始化 view_pager_fazenda ? @EdgarJr13 我使用“import kotlinx.android.synthetic.main.activity_fazendas_list.*”来直接获取布局的视图分页器。 @EdgarJr13 我更新了答案。可以检查 再次出现致命错误。这里的日志: java.lang.RuntimeException: 无法启动活动 ComponentInfobr.com.appintelipec/br.com.appintelipec.FazendaActivity: java.lang.IllegalStateException: Fragment FazendaListFragment524ae27 (2d05fa03-9307-423e-9a4d -616ecf00e3bf) 未附加到上下文。

以上是关于片段未附加到上下文的主要内容,如果未能解决你的问题,请参考以下文章

java.lang.IllegalStateException:未附加到上下文的片段

何时片段不附加到活动而仅附加到上下文?

传递嵌套在片段中的 AdapterView.OnItemClickListener() 中的活动上下文 - 方法未定义

使用意图共享后,片段未恢复其活动

如何重新附加片段(片段未附加到活动 Kotlin)

片段未附加到相应的片段