如何在Android App中修复从Fragment调用Activity的代码? [英] How can I fix the code to call Activity from Fragment in Android App?

查看:122
本文介绍了如何在Android App中修复从Fragment调用Activity的代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想从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-活动已经创建,这可能导致错误的方法排序.我假设onActivityCreatedonViewCreated之前(在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的代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆