问题描述
我想从Fragment调用Activity,以在Android应用程序中同时实现片段和活动之间的转换.
I would like to call Activity from Fragment to realize both transitions among fragments and activities simultaneously in an Android app.
我已经成功地从片段文件中调用了活动文件上的一种特定方法,但是我无法从片段中调用整个活动.
I have succeeded to call one specific method on activity file from fragment file, but I have trouble with calling an entire activity from a fragment.
每个页面上的基本功能
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
上,我尝试在下面调用整个FormActivity.
Errors and Problems
On Sample1Fragment.kt
, I tried to call Entire FormActivity on the below part.
但是显示了错误消息,我不知道要修复它来调用整个活动,而不是调用活动的方法.
However the error message is shown and I have no idea to fix it to call the entire activity rather than a method on an activity.
Unresolved reference: AppCompatActivity
我尝试从Sample1Fragment调用FromActivity的部分
The part where I tried to call FromActivity from Sample1Fragment
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之间进行转换.
What I can do now
I can call MainActivity.fragmentMethod()
from SampleFragment and transition between SampleFragment and Sample1Fragment with the following reference.
参考资料:科特林-如何从Android App中的片段调用活动方法?
Android Studio 3.6.1
Android Studio 3.6.1
成功构建了一个项目并在模拟器上运行该应用程序.但是,当我单击按钮以调用Sample1Fragment上的FormActivity时,屏幕突然关闭.
It was succeeded to build a project and run the app on the emulator.However, the screen was suddenly shut down when I click the button to call FormActivity on Sample1Fragment.
代码没有错误,所以我找不到任何解决方案.
There is no error on codes so I cannot find any solutions.
AndroidManifest.xml
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
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侦听器.与活动"不同,片段具有不同的生命周期和情形,当它们的View
尚未创建(或已经销毁)时,则更容易获得.
I think the problem here is that you're trying to set onClick listener too early.Fragments, unlike Activities, has different lifecycle and situations when their View
isn't created yet (or already destroyed) is much more easy to get.
有关详细信息,请查看此文档.
Check out this documentation for more info.
通常-开始与视图进行交互的最佳方法是onViewCreated
生命周期回调.在这里以及之后,您可以确定视图层次结构已准备就绪.
In general - best way to start interacting with views is the onViewCreated
lifecycle callback. Here, and afterward, you can be sure that the view hierarchy is ready.
在您的示例中,您已使用onActivityCreated
回调开始与视图进行交互.特别是,在SampleFragment
中设置onClick侦听器-btnClick.setOnClickListener(...)
.我认为在第一个片段中,它运作良好是因为它的创建与活动创建是一致的".
In your example, you've used onActivityCreated
callback to start interacting with views. In particular, setting onClick listener - btnClick.setOnClickListener(...)
in the SampleFragment
. And in the first fragment, I assume, it worked well because its creation was "aligned" with activity creation.
但是对于第二个片段-Sample1Fragment
-活动已经创建,这可能导致错误的方法排序.我假设onActivityCreated
在onViewCreated
之前(在onCreateView
上)被调用.并调用btnClick2.setOnClickListener(...)
导致崩溃,原因是btnClick2
尚未初始化.
But in the case of the second fragment - Sample1Fragment
- activity was already created, which probably resulted in wrong method ordering. I assume, onActivityCreated
was called earlier that onViewCreated
(on onCreateView
). And calling btnClick2.setOnClickListener(...)
resulted in crash, cause btnClick2
isn't initialized yet.
我的建议是将片段的与视图相关的代码移到onViewCreated
方法中.像这样:
My suggestion is to move view related code of your Fragments into onViewCreated
method(s). Having something like this:
override fun onViewCreated(view: View, savedInstanceState: Bundle) {
btnClick2.setOnClickListener(...)
}
这篇关于如何在Android App中修复从Fragment调用Activity的代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!