How to start a fragment from an activity - java

I am trying to run a class extending a fragment from a class extending AppCompactActivity, I have tried everything I have saw in Stackover flow and I cant get any to fix my problem. LineDetails is extending the Fragment
Progress1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Fragment fr = new LineDetails();
android.app.FragmentManager fm = getFragmentManager();
android.app.FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.fragment_place, fr);
fragmentTransaction.commit();
}
});
XML
<fragment android:name="com.almac.tracker.LineDetails"
android:id="#+id/fragment_place"
android:layout_width="match_parent"
android:layout_height="match_parent" />
PART OF XML FOR ACTIVITY CLASS
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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"
android:overScrollMode="never"
android:scrollbars="none"
tools:context=".Dashboard">
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/fragment_place">
</FrameLayout>
</RelativeLayout >

If your activity extends AppCompatActivity, then you cannot use getFragmentManager().
In fact you should get rid of classes in the package android.app such as android.app.FragmentManager. You should use the support classes from the package android.support.v4.app such as android.support.v4.app.FragmentManager
Use getSupportFragmentManager() instead of getFragmentManager()
The stack trace reports that you don't have any Layout with id R.id.fragment_place inside your activity. Check the xml of your activity and correct the id of fragment holder.

You're replacing instead of adding without a refresh, just do an add. I also simplified one of your useless variables and just went straight to ft instead of having an intermediate fm.
Progress1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Fragment fr = new LineDetails();
android.app.FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(R.id.fragment_place, fr);
ft.commit();
}
});

getSupportFragmentManager() should be used if activity extends AppcompatActivity
EDIT :
As per the Errors ! There is no View named fragment_place in the activity's layout that is #+id/fragment_place must exist in activity_main (If this is the layout attached to activity)

Double check your layout xml, It should have a FrameLayout with attribute #+id/fragment_place act as a placeholder for your LineDetails fragment.
If you already place <fragment /> in your layout, you don't need to replace() it programmatically.

Related

Can't call Fragment method in parent Activity

I simply want to call a method from a fragment in my MainActivity(parent).
But as soon as I try to call the method I get an NullPointerException.
Attempt to invoke virtual method 'void
com.example.fragmenttest.TestFragment.testMethod()' on a null object
reference
Here is what I do in the onCreate of the MainActivity:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.containerView, new TestFragment()).commit();
TestFragment fragment = (TestFragment) fragmentManager.findFragmentById(R.id.testfragment);
fragment.testMethod();
}
and here is the fragment:
#Nullable
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView=inflater.inflate(R.layout.activity_fragment,container,false);
return rootView;
}
public void testMethod(){
Toast.makeText(getContext(), "Test", Toast.LENGTH_LONG).show();
}
activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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=".MainActivity">
<FrameLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/containerView">
</FrameLayout>
</RelativeLayout>
and activity_fragment.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="com.example.fragmenttest.MainActivity"
android:id="#+id/testfragment">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="50dp"
android:text="Fragment" />
</RelativeLayout>
Of course this is not my real project, I just created a new one to simplify my issue.
In my real project I want to call a method from my fragment as soon as the onRewardedVideoCompleted method gets called, which is in my MainActivity.
How do I call the method from my fragment without getting a null pointer exception and without using an interface? (Using an interface for this small problem seems unnecessary)
Thanks
commit() is asynchronous. This is why your project is crashing upon launch. Instead of using commit(), use commitNow(). Also, instead of using new TestFragment(), create a variable so you can call its methods.
TestFragment testFragment= new TestFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.containerView, testFragment).commitNow();
testFragment.testMethod();
Fragment transactions are asynchronous (unless you use executePendingTransactions()). Your transaction has likely not completed yet. You use runOnCommit on FragmentTransaction (in the support library) to execute code after it is done.
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
TestFragment yourFragment = newe TestFragment();
fragmentTransaction.replace(R.id.containerView, yourFragment).commit();
yourFragment.testMethod();
First of all, You must pass yourFragment to fragmentTransaction, then you can call any methods you want.

How to control component visibility in Java android applications based on user role?

I'm implementing Android Java application in which there are two types of User. Each of them have permission to use some of the application features but not all of them.
My current implementation includes setting of all components visibility inside one activity every time user is redirected to that same activity. Example:
protected void onCreate(Bundle savedInstanceState) {
if(!userLoggedIn()) {
// Set all visibilities
} else if (loggedUserType() == UserType.USER1) {
// Set all visibilities
} else {
// Set all visibilities
}
}
Is there standard approach in android java applications that state how to deal with this issue? If not, is there any better approach than the one shown in example above?
you can have one fragment for each user type and show that fragment inside your activity.
inside your activity layout add a container.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent">
//rest of activty views
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</RelativeLayout>
and based on user type create and add your fragment
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExampleFragment fragment;
if(!userLoggedIn()) {
fragment = new ExampleFragment1();
} else if (loggedUserType() == UserType.USER1) {
fragment = new ExampleFragment2();
} else {
fragment = new ExampleFragment3 ();
}
fragmentTransaction.add(R.id.fragment_container, fragment);
fragmentTransaction.commit();
this way you will have clean architecture and can change each fragment separately

Which Fragment will be replaced when use fragmentTransaction.replace?

I have a activity_main.xml file:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="[URL]http://schemas.android.com/apk/res/android[/URL]"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<fragment
android:name="fragments"
android:id="#+id/lm_fragment"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_width="0dp"/>
<fragment
android:name="fragments"
android:id="#+id/pm_fragment"
android:layout_height="match_parent"
android:layout_width="0dp"
android:layout_weight="2"/>
</LinearLayout>
So I have 2 Fragment in my Activity
And when I add a Fragment in android.R.id.content, which Fragment will be added?
My Mainactivity.java:
if(config.orientation == Configuration.ORIENTATION_LANDSCAPE){
LM_Fragment lm_Fragment = new LM_Fragment();
fragmentTransaction.replace(android.R.id.content, lm_Fragment);
}else{
PM_Fragment pm_Fragment = new PM_Fragment();
fragmentTransaction.replace(android.R.id.content, pm_Fragment);
}
fragmentTransaction.commit();
}
LM_Fragment and PM_Fragment is used for Landscape mode and Portrait mode. And when I use fragmentTransaction.replace(android.R.id.content, lm_Fragment);
It will be added in 1 in 2 fragment which I specified in xml, but where lm_fragment or pm_fragment? Thank you!
Here is replace method signature
public abstract FragmentTransaction replace (int containerViewId, Fragment fragment)
You don't have such id android.R.id.content in your layout.
Thing is that you're using static fragments. But you need dynamic. Replace both fragment tag with single FrameLayout with id=android.R.id.content. Or better use your own id. E.g. "fragment_container", and then call
fragmentTransaction.replace(R.id.fragment_container, lm_Fragment);
and
fragmentTransaction.replace(R.id.fragment_container, pm_Fragment);

How to add fragment to existing fragment dynamically?

I want to add a fragment to an existing fragment on a button press (button sits on parent fragment) but I get an error: java.lang.ClassCastException: must implement OnFragmentInteractionListener.
What does that mean and why doesn't any of the example have it?
Parent fragment button press code:
Button interestedButton = (Button) myFragmentView.findViewById(R.id.interestedButton);
interestedButton.setOnClickListener(new View.OnClickListener() {
InterestedFormFragment interestedFormFragment = new InterestedFormFragment();
#Override
public void onClick(View v) {
FragmentTransaction fragmentTransaction = getFragmentManager().beginTransaction().add(R.id.interestedFrag_container, interestedFormFragment, "INTERESTED_FORM");
fragmentTransaction.commit();
}
});
Parent fragment XML:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#FFFFFF"
android:layout_gravity="bottom"
android:id="#+id/buildingPageId">
<LinearLayout
android:orientation="vertical"
android:id="#+id/interestedFrag_container"
android:layout_width="fill_parent"
android:layout_height="fill_parent"/>
...
The "interestedFrag_container" should hold the newly added child fragment.
My parent fragment isinflated and hold the button that should add the child.
What am I missing here?
Thank you!
Nested fragment are only added since API 17.
You can use getChildFragmentManager() to manage your nested fragments.

Android: simple replace fragment with an other fragment

I've run into an issue with my code.
What I want
My Activity starts automatically with Fragment01.
On Fragment01, there is a button, which should replace Fragment01 with Fragment02
What happens
When I press the button, instead of replacing Fragment01, I can still see Fragment01 in the background
MainActivity.java:
package com.lucky.fragmentexample;
import android.app.Activity;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
public class MainActivity extends Activity {
Button bn;
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bn = (Button)findViewById(R.id.button1);
bn.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
Fragment02 fragment02 = new Fragment02();
fragmentTransaction.replace(R.id.button_fragment_container, fragment02);
fragmentTransaction.commit();
}
});
}
}
activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<FrameLayout
android:id="#+id/button_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<fragment
android:id="#+id/fragment01"
android:name="com.lucky.fragmentexample.Fragment01"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</FrameLayout>
</LinearLayout>
Your fragment element in your layout XML can only ever refer to that single fragment and can't be swapped out in the way you intend. Instead, you need to remove the fragment element from your layout XML entirely and add your Fragment01 into your container FrameLayout in code in the onCreate() method of your activity.
So, remove the fragment element, like so;
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/LinearLayout1"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<FrameLayout
android:id="#+id/button_fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
</LinearLayout>
Then you can perform your transaction in the beginning of your onCreate() override, like so;
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
transaction.replace(R.id.button_fragment_container, new Fragment01());
transaction.commit();
You will want to instantiate a new FragmentTransaction for each new transaction, which means you'll probably want to remove the FragmentManager and FragmentTransaction from your instance members and declare them fresh each time you need to make a fragment transaction.
I hope this helps.
Further reading:
Official Fragments API Tutorial
Put beginTransaction inside onclick function and replace R.id.button_fragment_container for R.id.frame_container.
Use this inside onclick:
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.frame_container, new Fragment02()).commit();
Fragment inside xml file is not correct. Erase that part.
try this code :
FragmentManager fm = getFragmentManager();
FragmentTransaction fragmentTransaction = fm.beginTransaction();
fragmentTransaction.replace(R.id.fragment01, new Fragment02());
fragmentTransaction.commit();
also, change the 'fragment' to 'FrameLayout' in your xml. This prevents from any one fragment always remaining in the background.
Just go step by step:
First modify your layout, remove the fragment over there and make the reference of your FrameLayout in the activity.
Now initiate your fragment class which you want to add to the framelayout and call following code:
FragmentTransaction transaction = manager.beginTransaction();
transaction.remove(removePreviousFragmentIfAny);
transaction.add(R.id.button_fragment_container, newFragment);
transaction.commit();
Hope it will help you to go through.

Categories

Resources