Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to replace already opened fragment with new fragment in android studio?

I am trying to replace a MainFragment fragment with PickPowerFragement fragment but when I press the button in MainFragment to replace MainFragment with PickPowerFragment the app crashes. I was able to successfully load the PickPowerFragment in java as given in tutorial but the app crashes when I tried to do so in Kotlin (just for practice). So how can I replace the Fragment using Kotlin syntax

activity_hero_me.xml

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context="com.example.mandar.herome.Activities.HeroMe"
    tools:layout_editor_absoluteX="0dp"
    tools:layout_editor_absoluteY="25dp">

    <FrameLayout
        android:id="@+id/ReplaceFrame"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.0">

    </FrameLayout>
</android.support.constraint.ConstraintLayout>

HeroMe.kt

package com.example.mandar.herome.Activities

import android.app.Activity
import android.app.Fragment
import android.app.FragmentManager
import android.net.Uri
import android.os.Bundle
import com.example.mandar.herome.Fragments.MainFragment
import com.example.mandar.herome.Fragments.PickPowerFragment
import com.example.mandar.herome.R


class HeroMe : Activity() , MainFragment.OnMainFragmentInteractionListener , PickPowerFragment.pickPowerInteractionListener {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_hero_me)
        val manager : FragmentManager = fragmentManager
        var fragment : Fragment? = manager.findFragmentById(R.id.ReplaceFrame)
        if (fragment == null){
            fragment = MainFragment()
            manager.beginTransaction().add(R.id.ReplaceFrame,fragment).commit()
        }
    }

    fun loadPickPowerScreen(){
            var pickpowerfrag = PickPowerFragment()
            fragmentManager.beginTransaction().replace(R.id.ReplaceFrame, pickpowerfrag).addToBackStack(null).commit()
    }

    override fun onMainFragmentInteraction(uri: Uri) {

    }

    override fun onPickPowerInteraction(uri: Uri) {

    }

}

Here I am calling function loadPickPowerScreen() from MainFragment

I tested If the button( a button I am using to replace MainFragment with pickPowerFragment) works right or not by using it to modify the text on it when the button is clicked and it seems to work just fine.So I guess there shouldn't be any problem with MainFragment.kt

Here is onClick() method from MainFragment.kt

var onClick = View.OnClickListener(){view ->
    var heroActivity : HeroMe = HeroMe()
    heroActivity.loadPickPowerScreen()
}

and here is fragment PickPowerFragment.kt

package com.example.mandar.herome.Fragments

import android.app.Fragment
import android.content.Context
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import com.example.mandar.herome.R

/**
 * A simple [Fragment] subclass.
 * Activities that contain this fragment must implement the
 * [PickPowerFragment.OnFragmentInteractionListener] interface
 * to handle interaction events.
 * Use the [PickPowerFragment.newInstance] factory method to
 * create an instance of this fragment.
 */
class PickPowerFragment : Fragment() {

    // TODO: Rename and change types of parameters
    private var mParam1: String? = null
    private var mParam2: String? = null

    private var mListener: pickPowerInteractionListener? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        if (arguments != null) {
            mParam1 = arguments.getString(ARG_PARAM1)
            mParam2 = arguments.getString(ARG_PARAM2)
        }
    }

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

    // TODO: Rename method, update argument and hook method into UI event
    fun onButtonPressed(uri: Uri) {
        if (mListener != null) {
            mListener!!.onPickPowerInteraction(uri)
        }
    }

    override fun onAttach(context: Context?) {
        super.onAttach(context)
        if (context is pickPowerInteractionListener) {
            mListener = context
        } else {
            throw RuntimeException(context!!.toString() + " must implement OnFragmentInteractionListener")
        }
    }

    override fun onDetach() {
        super.onDetach()
        mListener = null
    }

    /**
     * This interface must be implemented by activities that contain this
     * fragment to allow an interaction in this fragment to be communicated
     * to the activity and potentially other fragments contained in that
     * activity.
     *
     *
     * See the Android Training lesson [Communicating with Other Fragments](http://developer.android.com/training/basics/fragments/communicating.html) for more information.
     */
    interface pickPowerInteractionListener {
        // TODO: Update argument type and name
        fun onPickPowerInteraction(uri: Uri)
    }

    companion object {
        // TODO: Rename parameter arguments, choose names that match
        // the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
        private val ARG_PARAM1 = "param1"
        private val ARG_PARAM2 = "param2"

        /**
         * Use this factory method to create a new instance of
         * this fragment using the provided parameters.
         *
         * @param param1 Parameter 1.
         * @param param2 Parameter 2.
         * @return A new instance of fragment PickPowerFragment.
         */
        // TODO: Rename and change types and number of parameters
        fun newInstance(param1: String, param2: String): PickPowerFragment {
            val fragment = PickPowerFragment()
            val args = Bundle()
            args.putString(ARG_PARAM1, param1)
            args.putString(ARG_PARAM2, param2)
            fragment.arguments = args
            return fragment
        }
    }
}// Required empty public constructor

logcat after the crash: Logcat after the crash:

Information provided by debugger just before the crash: debugger variable values just before crash

Here I add Git Repository link for project Git Android Project: HeroMe

like image 505
Mandar Sadye Avatar asked Dec 08 '22 16:12

Mandar Sadye


2 Answers

After 2 days of digging, I finally found the solution for my problem. There is just one error I made in the onClick method while converting Java to Kotlin that is resulting in the crash.

Instead of :

var onClick = View.OnClickListener(){view ->
    var heroActivity : HeroMe = HeroMe()
    heroActivity.loadPickPowerScreen()
}

The code should have been :

var onClick = View.OnClickListener(){view ->
    var heroActivity : HeroMe= activity as HeroMe
    heroActivity.loadPickPowerScreen()
}

Thank you for everyone who tried to help me.


Clarification for why this code works:

when you write,

var heroActivity : HeroMe = HeroMe()

because of constructor it actually create other object(activity) which is not the same activity which actually loaded. So this new activity is created but not displayed because no startActivity method is called. So,

heroActivity.loadPickPowerScreen()

This method is called on activity which is not started.

Now, this line

var heroActivity : HeroMe= activity as HeroMe

is similar to

getActivity()

form java, which returns the parent activity of fragment. Return type is Activity so we need to case it so we can call functions in that activity.

like image 118
Mandar Sadye Avatar answered Dec 10 '22 11:12

Mandar Sadye


for fragment adding

  getSupportFragmentManager().beginTransaction().add(R.id.container,FragmentLogin()).commit();

for fragment replacing

 getSupportFragmentManager().beginTransaction().replace(R.id.container,FragmentLogin()).commit()
like image 24
Prabh deep Avatar answered Dec 10 '22 12:12

Prabh deep