如何修复代码以从 Android 应用程序中的 Fragment 调用 Activity?

How can I fix the code to call Activity from Fragment in Android App?

我想做什么

我想从 Fragment 调用 Activity 以在 Android 应用程序中同时实现片段和活动之间的转换。

我已经成功地从片段文件调用 activity 文件的一个特定方法,但我无法从片段调用整个 activity。

各页基本功能

SampleFragment - MainActivity's fragmentMethod() is called once  the button is clicked on the page
Sample1Fragment - FormActivity is called once the button is clicked on the page
FormActivity - FormActivity2 is called once the button is clicked on the page

错误和问题

Sample1Fragment.kt,我尝试在下面的部分调用 Entire FormActivity。

但是显示了错误消息,我不知道如何修复它以调用整个 activity 而不是 activity.

上的方法
Unresolved reference: AppCompatActivity

我尝试从 Sample1Fragment

调用 FromActivity 的部分
    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        btnClick2.setOnClickListener(object:View.OnClickListener{

            // here I would like to move to FormActivity
            override fun onClick(v: View?) {
                (activity as FormActivity).AppCompatActivity()
            }

        })
    }

当前代码

MainActivity.kt

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Toast
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // make the list of fragment
        val fragmentList = arrayListOf<Fragment>(
            SampleFragment(),
            Sample1Fragment()
        )

        // create instance of adapter
        val adapter = SamplePagerAdapter(supportFragmentManager, fragmentList)
        /// set adapter
        viewPager.adapter = adapter
    }



    public fun fragmentMethod() {
        Toast.makeText(this@MainActivity, "Method called From Fragment", Toast.LENGTH_LONG).show();
    }
}

SamileFragment.kt

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_sample.*

class SampleFragment : Fragment() {


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        arguments?.let {

        }
    }

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

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        btnClick.setOnClickListener(object:View.OnClickListener{
            override fun onClick(v: View?) {
                (activity as MainActivity).fragmentMethod()
            }

        })
    }



}

Sample1Fragment.kt

import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_sample1.*

class Sample1Fragment : Fragment() {

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

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        btnClick2.setOnClickListener(object:View.OnClickListener{

            // here I would like to move to FormActivity
            override fun onClick(v: View?) {
                (activity as FormActivity).AppCompatActivity()
            }

        })
    }

}

SamplePagerAdapter.kt

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.FragmentStatePagerAdapter

class SamplePagerAdapter(fm: FragmentManager, private val fragmentList: List<Fragment>) :
    FragmentStatePagerAdapter(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT) {

    // control fragment to show
    override fun getItem(position: Int): Fragment {
        return fragmentList[position]
    }

    // the size of contents(fragment list) to set viewPager
    override fun getCount(): Int {
        return fragmentList.size
    }
}

FormActivity.kt

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.app.Activity
import android.content.Intent
import android.util.Log
import kotlinx.android.synthetic.main.activity_form.*

class FormActivity : AppCompatActivity() {

    companion object {
        const val EXTRA_MESSAGE = "com.example.kotlinactivitydatatrans.MESSAGE"
    }

    private val RESULT_SUBACTIVITY = 1000

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

        button.setOnClickListener {
            if (editText.text != null) {
                val intent = Intent(applicationContext, FormActivity2::class.java)
                val str = editText.text.toString()
                Log.d("debug",str)

                intent.putExtra(EXTRA_MESSAGE, str)
                startActivityForResult(intent, RESULT_SUBACTIVITY)

                editText.setText("")

            }
        }
    }

    // to get a result form SubActivity
    override fun onActivityResult(requestCode: Int, resultCode: Int, intent: Intent?) {
        super.onActivityResult(requestCode, resultCode, intent)

        if (resultCode == Activity.RESULT_OK &&
            requestCode == RESULT_SUBACTIVITY && intent != null) {

            val res = intent.extras?.getString(EXTRA_MESSAGE)?: ""
            textView.text = res
        }
    }
}

我现在能做什么

我可以从 SampleFragment 调用 MainActivity.fragmentMethod() 并使用以下参考在 SampleFragment 和 Sample1Fragment 之间转换。

参考:Kotlin-How to call an activity method from fragment in Android App?

开发环境

Android Studio 3.6.1

阅读评论后我尝试做的事情

新麻烦

在模拟器上构建项目和运行应用程序成功。 但是,当我在Sample1Fragment.

上点击调用FormActivity的按钮时,屏幕突然关机了

代码没有错误,所以我找不到任何解决方案。

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.fragact">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
            <activity android:name=".FormActivity"
            android:label="@string/app_name"
            tools:ignore="WrongManifestParent">
            </activity>
            <activity android:name=".FormActivity2"
                android:label="@string/app_name"
                tools:ignore="WrongManifestParent">
            </activity>
    </application>
</manifest>

fragment_sample1.xml

<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=".Sample1Fragment">

    <TextView
        android:id="@+id/textView2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="32dp"
        android:text="Sample1Fragment"
        android:textSize="36sp" />

    <Button
            android:id="@+id/btnClick2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:gravity="center"
            android:layout_gravity="center"
            android:background="@color/colorPrimary"
            android:textColor="#FFF"
            android:textAllCaps="false"
            android:minEms="8"
            android:text="Call Activity"/>

    </FrameLayout>

Logcat

2020-03-10 18:50:48.622 9917-9917/com.example.fragact W/ActivityThread: handleWindowVisibility: no activity for token android.os.BinderProxy@f79aa98
2020-03-10 20:50:48.659 9917-9917/com.example.fragact D/AndroidRuntime: Shutting down VM
2020-03-10 20:50:48.661 9917-9917/com.example.fragact E/AndroidRuntime: FATAL EXCEPTION: main
    Process: com.example.fragact, PID: 9917
    java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.fragact/com.example.fragact.FormActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2913)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048)
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808)
        at android.os.Handler.dispatchMessage(Handler.java:106)
        at android.os.Looper.loop(Looper.java:193)
        at android.app.ActivityThread.main(ActivityThread.java:6669)
        at java.lang.reflect.Method.invoke(Native Method)
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493)
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858)
     Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'void android.widget.Button.setOnClickListener(android.view.View$OnClickListener)' on a null object reference
        at com.example.fragact.FormActivity.onCreate(FormActivity.kt:22)
        at android.app.Activity.performCreate(Activity.java:7136)
        at android.app.Activity.performCreate(Activity.java:7127)
        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2893)
        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3048) 
        at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78) 
        at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108) 
        at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68) 
        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1808) 
        at android.os.Handler.dispatchMessage(Handler.java:106) 
        at android.os.Looper.loop(Looper.java:193) 
        at android.app.ActivityThread.main(ActivityThread.java:6669) 
        at java.lang.reflect.Method.invoke(Native Method) 
        at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:493) 
        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:858) 
2020-03-10 20:50:48.679 9917-9917/com.example.fragact I/Process: Sending signal. PID: 9917 SIG: 9

我认为这里的问题是您试图过早地设置 onClick 侦听器。 Fragments 与 Activity 不同,具有不同的生命周期和情况,当它们的 View 尚未创建(或已被销毁)时更容易获得。

查看 this 文档了解更多信息。

通常 - 开始与视图交互的最佳方式是 onViewCreated 生命周期回调。在这里和之后,您可以确定视图层次结构已准备就绪。

在您的示例中,您使用了 onActivityCreated 回调来开始与视图交互。特别是在 SampleFragment 中设置 onClick 侦听器 - btnClick.setOnClickListener(...)。在第一个片段中,我认为它运行良好,因为它的创建是 "aligned" 和 activity 创建。

但是对于第二个片段 - Sample1Fragment - activity 已经创建,这可能导致错误的方法排序。我假设 onActivityCreatedonViewCreated 之前被调用(在 onCreateView 上)。并且调用 btnClick2.setOnClickListener(...) 导致崩溃,因为 btnClick2 尚未初始化。

我的建议是将片段的视图相关代码移动到 onViewCreated 方法中。有这样的东西:

override fun onViewCreated(view: View, savedInstanceState: Bundle) {
    btnClick2.setOnClickListener(...)
}