如何修复代码以从 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 已经创建,这可能导致错误的方法排序。我假设 onActivityCreated
在 onViewCreated
之前被调用(在 onCreateView
上)。并且调用 btnClick2.setOnClickListener(...)
导致崩溃,因为 btnClick2
尚未初始化。
我的建议是将片段的视图相关代码移动到 onViewCreated
方法中。有这样的东西:
override fun onViewCreated(view: View, savedInstanceState: Bundle) {
btnClick2.setOnClickListener(...)
}
我想做什么
我想从 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 已经创建,这可能导致错误的方法排序。我假设 onActivityCreated
在 onViewCreated
之前被调用(在 onCreateView
上)。并且调用 btnClick2.setOnClickListener(...)
导致崩溃,因为 btnClick2
尚未初始化。
我的建议是将片段的视图相关代码移动到 onViewCreated
方法中。有这样的东西:
override fun onViewCreated(view: View, savedInstanceState: Bundle) {
btnClick2.setOnClickListener(...)
}