Как я могу исправить код для вызова Activity из фрагмента в Android App? - PullRequest
0 голосов
/ 10 марта 2020

Что я хотел бы сделать

Я хотел бы вызвать Activity из фрагмента, чтобы реализовать одновременно переходы между фрагментами и действиями в приложении Android.

Мне удалось вызвать один конкретный c метод для файла действий из файла фрагмента, но у меня возникают проблемы с вызовом всей операции из фрагмента.

Basi c Функции на каждой странице

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 в приведенной ниже части.

Однако отображается сообщение об ошибке, и я понятия не имею, как его исправить вызывать все действие, а не метод в действии.

Unresolved reference: AppCompatActivity

Часть, в которой я пытался вызвать FromActivity из 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
        }
    }
}

Что я могу сделать сейчас

Я могу вызвать MainActivity.fragmentMethod() из SampleFragment и перейти между SampleFragment и Sample1Fragment со следующей ссылкой.

Ссылка: Kotlin -Как вызвать метод действия из фрагмента в Android App?

screen1 screen2

Среда разработки

Android Studio 3.6.1

Что я пытался сделать после прочтения комментариев

Новая проблема

Удалось построить проект и запустить приложение на эмуляторе. Однако экран внезапно отключился, когда я нажал кнопку, чтобы вызвать FormActivity для Sample1Fragment.

В кодах нет ошибок, поэтому я не могу найти решения.

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>

фрагмент_ образца1. 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

1 Ответ

1 голос
/ 10 марта 2020

Я думаю, что проблема в том, что вы пытаетесь настроить прослушиватель onClick слишком рано. Фрагменты, в отличие от Деятельности, имеют другой жизненный цикл, и ситуации, когда их View еще не созданы (или уже уничтожены), получить намного проще.

Ознакомьтесь с этой документацией, чтобы узнать больше info.

В общем, лучший способ начать взаимодействие с представлениями - это обратный вызов жизненного цикла onViewCreated. Здесь и далее вы можете быть уверены, что иерархия представлений готова.

В вашем примере вы использовали обратный вызов onActivityCreated, чтобы начать взаимодействие с представлениями. В частности, настройка прослушивания onClick - btnClick.setOnClickListener(...) в SampleFragment. И в первом фрагменте, я полагаю, он работал хорошо, потому что его создание было «выровнено» с созданием активности.

Но в случае второго фрагмента - Sample1Fragment - действие уже было создано, что, вероятно, привело к в неправильном порядке заказа. Я предполагаю, что onActivityCreated ранее назывался onViewCreated (onCreateView) А вызов btnClick2.setOnClickListener(...) привел к cra sh, причина btnClick2 еще не инициализирована.

Я предлагаю перенести связанный с просмотром код ваших фрагментов в onViewCreated метод (ы). Имея что-то вроде этого:

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