I have an activity (MainActivity) which extends AppCompatActivity because I am using some of the material design elements in my app.
I then have an array adapter with a few fields and a button. This adapter has a separate view and is injected into my MainActivity layout.
When I click the button on the adapter view, I want to open a new fragment which displays a bunch of text, however, I can't seem to do this and I think it is because I am not extending FragmentActivity in my MainActivity? I read on another post that I should be able to extend AppCompatActivity and still be able to reference the fragment manager...here is my code to open the fragment:
In my custom array adapter, onClick() of a button:
holder.desc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
JobDescFragment fragment= new JobDescFragment();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
});
The error I get is that it cannot resolve getSupportFragmentManager(). What am I doing wrong?
I am importing android.support.v4.app.Fragment and .FragmentManager in my adapter.
Thanks in advance for the help!
EDIT:
<merge
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">
<com.lorentzos.flingswipe.SwipeFlingAdapterView
android:id="#+id/frame"
android:background="#color/laborswipe_lightgray"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:context=".MainActivity"
android:layout_gravity="top" />
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</merge>
you can try this
FragmentTransaction ft = ((AppCompatActivity) mContext).getSupportFragmentManager()
.beginTransaction();
In kotlin it will be like this for example. I have tried it and it work perfectly
val dialog = IntervAddFragment()//The fragment that u want to open for example
val ft = (context as AppCompatActivity).supportFragmentManager.beginTransaction()
dialog.show(ft, ContentValues.TAG)
Hi this is simple just pass the reference of YourParent Activity
Just use the snippet like this below in Your Adapter class to open fragment
Fragment fragment = new YourFragment();
FragmentManager fm = ((MainActivity) mContext).getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.frame_container, fragment);
ft.commit();
in adapter use
appCompatActivity object instead of context
it will work
pass context in adapter and use
context.getSupportFragmentManager().beginTransaction();
avoid unwanted codes
public class AdapterRecyclerViewDoc extends RecyclerView.Adapter<AdapterRecyclerViewDoc.ShareDocViewHolder> {
ArrayList<ModelDoc> arrayList;
AppCompatActivity appCompatActivity;
public AdapterRecyclerViewDoc(ArrayList<ModelDoc> arrayList, AppCompatActivity appCompatActivity) {
this.arrayList=arrayList;
this.appCompatActivity=appCompatActivity;
}
#Override
public ShareDocViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(parent.getContext()).inflate
(R.layout.recyclerview_item_doc, parent, false);
ShareDocViewHolder eventViewHolder = new ShareDocViewHolder(v);
this.appCompatActivity.getSupportFragmentManager();
return eventViewHolder;
}
To make the code more flexible and separate logic you should understand responsibilities of your components. It is clear that your Adapter should not know about the Fragment and what is base class of Activity. So what should you do?
In your Activity you should set a listener to item clicked event inside adapter:
public class YourActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_your);
//... some findViewById, etc.
YourAdapter adapter = new YourAdapter(this, data, new OnDetailsRequestListener(){
public void onDetailsRequested(int itemId){
DetailsFragment fragment = DetailsFragment.newInstance(itemId);
getSupportFragmentManager().beginTransaction()
.replace(R.id.fragment_container, fragment)
.addToBackStack(null)
.commit();
});
//... recyclerView.setAdapter ... etc.
}
public interface onDetailsRequestListener{
void onDetailsRequestLister(int itemId);//here could be whatever you want, itemId, details, whatever...
}
}
And inside your adapter you would have:
//...
public AdapterConstructor(Context context, ArrayList data, YourActivity.OnDetailsRequestListener detailsRequestListener) {
this.data = data;
this.context = context;
this.detailsRequestListener = detailsRequestListener;
//...
}
//Inside bindView
holder.desc.setTag(position);
holder.desc.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
int position = (int)view.getTag();
int itemId = data.get(position).getId();
detailsRequestListener.onDetailsRequested(itemId);
}
});
From your class
YourAdapter=new YourAdapter(context, list, YourClass.this.getSupportFragmentManager)
Adapter
public Adapter(context, list, FragmentManager manager){
this.manager=manager;
Action
FragmentTransaction ft = fragmentcontext.beginTransaction();
SlideshowDialogFragment newFragment = SlideshowDialogFragment.newInstance();
newFragment.setArguments(bundle);
newFragment.show(ft, "slideshow");
FragmentTransaction trans =((FragmentActivity)context).getSupportFragmentManager()
.beginTransaction();
If you try this, you will see it work.
Related
I'm trying to make an app where I've a RecyclerView with the options to remove the objects and add random numbers. What I'm trying to do is show a fragment when any member of the recycler view list is clicked. I'm getting the error " java.lang.IllegalStateException: Activity has been destroyed".
I'm pretty shure I'm doing something very wrong.
What I tried to do is putting a call to the change fragment method on my AnimalsAdapter class. I'm letting the code below and a github link.
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.berna.recyclerviewtp2, PID: 18705
java.lang.IllegalStateException: Activity has been destroyed
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:2114)
at android.support.v4.app.BackStackRecord.commitInternal(BackStackRecord.java:683)
at android.support.v4.app.BackStackRecord.commit(BackStackRecord.java:637)
at com.example.berna.recyclerviewtp2.MainActivity.changeFragment(MainActivity.java:148)
at com.example.berna.recyclerviewtp2.AnimalsAdapter$1.onClick(AnimalsAdapter.java:81)
at android.view.View.performClick(View.java:6597)
at android.view.View.performClickInternal(View.java:6574)
at android.view.View.access$3100(View.java:778)
at android.view.View$PerformClick.run(View.java:25885)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
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)
My Code Main class changeFragment:
public void changeFragment(View view){
Fragment fragment;
FragmentOne fragmentOne = new FragmentOne();
fragment = fragmentOne;
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.fragment,fragment);
ft.addToBackStack(null);
ft.commit();
FragmentOne class code:
public class FragmentOne extends Fragment {
#Override
public View onCreateView (LayoutInflater inflater, ViewGroup container, Bundle savedInstaceState){
//Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_blank,container,false);
}
}
Click Listener code:
// Set a click listener for TextView
holder.mTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
new MainActivity().changeFragment(view);
//String animal = mDataSet.get(position);
//Toast.makeText(mContext,animal,Toast.LENGTH_SHORT).show();
}
});
What I have to do to achieve the fragment when pressing the recyclerview member?
Original code I'm using to try what I'm trying
Github link for complete project
You should never instantiate your activity this way: new MainActivity().changeFragment(view);, it will never initialise properly. So it's either you delegate the listener, or find another work around for the callback.
For example, create an interface for callback:
interface ItemClickListener {
void onItemClick(View v);
}
Let your MainActivity implements the interface:
public class MainActivity extends Activity implements ItemClickListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
mAdapter = new AnimalsAdapter(mContext, animalsList, this);
// ...
}
#Override
public void onItemClick(View view) {
changeFragment(view);
}
}
Then allow your adapter to take ItemClickListener as a parameter:
private ItemClickListener callback;
public AnimalAdapter(Context context, List<String> data, ItemClickListener callback) {
this.callback = callback;
And let your holder.mTextView to forward the callback (back to activity):
holder.mTextView.setOnClickListener(callback::onItemClick);
You should create fragment after activity created, that is a basic knowledge about activity life cycle.
holder.mTextView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Intent intent = new Intent(your_current_activity, MainActivity.class);
intent.putExtras(extras);
startActivity(intent);
}
});
then replace fragment in onCreate() of MainActivity
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_activity_layout);
changeFragment(null); //because we don't using parameter view
}
If you have any problem else, please comment below.
You need two changes in your code.
1. Create an interface for click listener.
2. If you want to replace fragment then you need one more Layout in XML
We solve the first issue.
1. Create an interface for click listener.
Below are some change you need to do in your adapter,
Create Interface in your adapter
public interface RecyclerItemInteraction {
void onChangeFragmentClick();
}
The second change will pass this interface.
Deeclare gloabal variable
private RecyclerItemInteraction mInteraction;
public AnimalsAdapter(Context context,List list,RecyclerItemInteraction interaction){
mDataSet = list;
mContext = context;
mInteraction = interaction;
}
Replace this below line
new MainActivity().changeFragment(view); : Remove it
if (mInteraction!=null)mInteraction.onChangeFragmentClick(); add this line.
Now Go to your MainActivity and add below line
mAdapter = new AnimalsAdapter(mContext, animalsList,this);
You can see that add third parameter this.
Now override this method and enjoy your day.
#Override
public void onChangeFragmentClick() {
Fragment fragment;
FragmentOne fragmentOne = new FragmentOne();
fragment = fragmentOne;
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.replace(R.id.container,fragment);
ft.addToBackStack(null);
ft.commit();
}
If you want to replace fragment then you need one more Layout in XML
Add this line to your main_activity.xml layout.
I am having trouble opening a fragment from within another fragment on the click of a button. Everything seems to make sense (to me) and I have tried playing about with my code (changing the layouts, replacing fragments etc) but nothing is working.
Here is my RoleFragment.java (The fragment which contains the button)
public class RolesFragment extends Fragment implements View.OnClickListener {
GridView gridView;
ArrayList<Players> playersList;
MyAdapter adapter;
#Override
public View onCreateView(LayoutInflater inflater,ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_viewroles, container, false);
gridView = (GridView) view.findViewById(R.id.gv_players);
Button nightround = (Button) view.findViewById(R.id.buttonNightRound);
nightround.setOnClickListener(this);
DatabaseHelper databaseHelper = new DatabaseHelper(getActivity());
playersList = new ArrayList<Players>();
playersList = databaseHelper.getPlayers();
adapter = new MyAdapter(getActivity(), playersList);
gridView.setAdapter(adapter);
return view;
}
#Override
public void onClick(View v) {
Fragment fragment = null;
switch (v.getId()) {
case R.id.buttonNightRound:
fragment = new NightRound();
replaceFragment(fragment);
break;
}
}
public void replaceFragment(Fragment someFragment) {
FragmentTransaction transaction = getFragmentManager().beginTransaction();
transaction.replace(R.id.fragment_container, someFragment);
transaction.addToBackStack(null);
transaction.commit();
}
}
And this is my fragment_viewroles.xml file.
<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"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context="com.example.tuss.mafia.GameActivity" >
<Button
android:id="#+id/buttonNightRound"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Night Round"
android:onClick="FragmentNightRoundClick"
android:clickable="true"
android:layout_weight="2"/>
<GridView
android:id="#+id/gv_players"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="auto_fit"
android:stretchMode="columnWidth"
android:columnWidth="150dp"
android:horizontalSpacing="10dp"
android:verticalSpacing="10dp"
android:gravity="center"
android:layout_below="#id/buttonNightRound">
</GridView>
</RelativeLayout>
The trouble is, when I click the button nothing happens.
There some problems here.
First, you have to add a container with the id R.id.fragment_container inside your fragment like FrameLayout
which will store your new fragment.
If your want to open a fragment as a new screen, you have to put it inside a new activity. Fragments are piece of screens and should not be used without activities or view pagers.
Have a look at the Android deverlopers page: http://developer.android.com/training/basics/fragments/communicating.html#DefineInterface
Basically, you define an interface in your Fragment A, and let your Activity implement that Interface. Now you can call the interface method in your Fragment, and your Activity will receive the event. Now in your activity, you can call your second Fragment to update the textview with the received value
// You Activity implements your interface
public class YourActivity implements FragmentA.TextClicked{
#Override
public void sendText(String text){
// Get Fragment B
FraB frag = (FragB)
getSupportFragmentManager().findFragmentById(R.id.fragment_b);
frag.updateText(text);
}
}
// Fragment A defines an Interface, and calls the method when needed
public class FragA extends Fragment{
TextClicked mCallback;
public interface TextClicked{
public void sendText(String text);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
mCallback = (TextClicked) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement TextClicked");
}
}
public void someMethod(){
mCallback.sendText("YOUR TEXT");
}
#Override
public void onDetach() {
mCallback = null; // => avoid leaking, thanks #Deepscorn
super.onDetach();
}
}
// Fragment B has a public method to do something with the text
public class FragB extends Fragment{
public void updateText(String text){
// Here you have it
}
}
Try something like the following:
Fragment fragment = OtherFragment.newInstance();
android.support.v4.app.FragmentTransaction transaction = getActivity().getSupportFragmentManager().beginTransaction();
transaction.replace(R.id.container_layout, fragment, "OtherFragment");// give your fragment container id in first parameter
transaction.addToBackStack(null); // if written, this transaction will be added to backstack
transaction.commit();
I'm new in android. I have a navigation drawer where i used recyclerview for the item. I have three tabs representing three fragments in a viewpager. My problem is that i can not open a fragment by clicking recycler view item. And another problem is that I tried FragmentTransaction but don't know how to get the fragment id. Please help me i'm stuck on it.You can give me any tutorial link.
Here is my code...
In my recyclerview adapter i have tried:
public void onBindViewHolder(MyViewHandler holder, int position) {
final Information current = data.get(position);
holder.title.setText(current.title);
holder.icon.setImageResource(current.iconId);
holder.title.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
fragmentJump(current);
}
});
}
private void fragmentJump(Information mItemSelected) {
mFragment = new FragmentIncome();
mBundle = new Bundle();
mBundle.putParcelable("item_selected_key", mItemSelected);// here my Information class is not parcelable how to solve it?
mFragment.setArguments(mBundle);
switchContent(R.id.frag1, mFragment);/// Here how to get the fragment id in R.id.frag1 of viewpager
}
public void switchContent(int id, Fragment fragment) {
if (mContext == null)
return;
if (mContext instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) mContext;
Fragment frag = fragment;
mainActivity.switchContent(id, frag);
}
}
And in the MainActivity i have created this method:
public void switchContent(int id, Fragment fragment) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(id, fragment, fragment.toString());
ft.addToBackStack(null);
ft.commit();
}
I have followed this link how to open a different fragment on recyclerview OnClick
You can do this by using interface callback when a recyclerview item is clicked:
You could do this:
class NavdrawerRecyclerAdapter extends RecyclerView.Adapter<> {
private OnFragmentInteractionListener mListener;
public NavdrawerRecyclerAdapter(OnFragmentInteractionListener listener){
mListner = listner;
}
//call and pass position inside onClick
public void onRecyclerItemClicked(int pos){
mListener.openFragment(pos);
}
public interface OnFragmentInteractionListener{
public void openFragment(int pos);
}}
Now your mainactivity which has tablayouts implement this interface.
public class MainActivity extends AppCompatActivity implements NavdrawerRecyclerAdapter.OnFragmentInteractionListener{
NavdrawerRecyclerAdapter adapter = new NavdrawerRecyclerAdapter(this);
#override
openFragment(int position){
TabLayout.Tab tab = tabLayout.getTabAt(position);
tab.select();
}
}
Try it and tell me if this works.
I'm trying to display a ListFragment that'll show user comments from within another Fragment. For testing purposes, I'm calling the ListFragment using an "onClick" method from within the parent Fragment. However, I can't seem to get the ListFragment to show, as it has no "show" method. Are there any obvious problems with my code that I can fix?
This is the method called when I click a button to show the ListFragment.
private void showComments(JSONArray comments) {
ListFragment newFragment = CommentsFragment.newInstance(comments);
}
And here is the ListFragment itself.
public class CommentsFragment extends ListFragment {
public static CommentsFragment newInstance(JSONArray passedComments) {
CommentsFragment f = new CommentsFragment();
ArrayList<String> adapter = convertJSON(passedComments);
Bundle args = new Bundle();
args.putStringArrayList("adapter", adapter);
f.setArguments(args);
return f;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Bundle args = new Bundle();
ArrayList<String> commentsArray = args.getStringArrayList("adapter");
ArrayAdapter<String> commentsAdapter = new ArrayAdapter<String>(
getActivity(), R.layout.comments_list,
commentsArray);
setListAdapter(commentsAdapter);
}
You have to commit the ListFragment with a FragmentManager, and also have a layout in the XML that will contain it.
Firstly add a FrameLayout to the XML where you want the ListFragment placed, and afterwards use getChildFragmentManager() to get a FragmentManager, that you can place the ListFragment with.
Try like this
private void showComments(JSONArray comments) {
ListFragment newFragment = CommentsFragment.newInstance(comments);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, newFragment);
fragmentTransaction.commit();
}
I want to add a Fragment to an Activity that implements its layout programmatically. I looked over the Fragment documentation but there aren't many examples describing what I need. Here is the type of code I tried to write:
public class DebugExampleTwo extends Activity {
private ExampleTwoFragment mFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frame = new FrameLayout(this);
if (savedInstanceState == null) {
mFragment = new ExampleTwoFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(frame.getId(), mFragment).commit();
}
setContentView(frame);
}
}
...
public class ExampleTwoFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
Button button = new Button(getActivity());
button.setText("Hello There");
return button;
}
}
This code compiles but crashes at start, probably because my FragmentTransaction.add() is incorrect. What is the correct way to do this?
It turns out there's more than one problem with that code. A fragment cannot be declared that way, inside the same java file as the activity but not as a public inner class. The framework expects the fragment's constructor (with no parameters) to be public and visible. Moving the fragment into the Activity as an inner class, or creating a new java file for the fragment fixes that.
The second issue is that when you're adding a fragment this way, you must pass a reference to the fragment's containing view, and that view must have a custom id. Using the default id will crash the app. Here's the updated code:
public class DebugExampleTwo extends Activity {
private static final int CONTENT_VIEW_ID = 10101010;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FrameLayout frame = new FrameLayout(this);
frame.setId(CONTENT_VIEW_ID);
setContentView(frame, new LayoutParams(
LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));
if (savedInstanceState == null) {
Fragment newFragment = new DebugExampleTwoFragment();
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(CONTENT_VIEW_ID, newFragment).commit();
}
}
public static class DebugExampleTwoFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
EditText v = new EditText(getActivity());
v.setText("Hello Fragment!");
return v;
}
}
}
Here is what I came up with after reading Tony Wong's comment:
public class DebugExampleTwo extends BaseActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addFragment(android.R.id.content,
new DebugExampleTwoFragment(),
DebugExampleTwoFragment.FRAGMENT_TAG);
}
}
...
public abstract class BaseActivity extends Activity {
protected void addFragment(#IdRes int containerViewId,
#NonNull Fragment fragment,
#NonNull String fragmentTag) {
getSupportFragmentManager()
.beginTransaction()
.add(containerViewId, fragment, fragmentTag)
.disallowAddToBackStack()
.commit();
}
protected void replaceFragment(#IdRes int containerViewId,
#NonNull Fragment fragment,
#NonNull String fragmentTag,
#Nullable String backStackStateName) {
getSupportFragmentManager()
.beginTransaction()
.replace(containerViewId, fragment, fragmentTag)
.addToBackStack(backStackStateName)
.commit();
}
}
...
public class DebugExampleTwoFragment extends Fragment {
public static final String FRAGMENT_TAG =
BuildConfig.APPLICATION_ID + ".DEBUG_EXAMPLE_TWO_FRAGMENT_TAG";
// ...
}
Kotlin
If you are using Kotlin make sure to take a look at what the Kotlin extensions by Google provide or just write your own.
public class Example1 extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DemoFragment fragmentDemo = (DemoFragment)
getSupportFragmentManager().findFragmentById(R.id.frame_container);
//above part is to determine which fragment is in your frame_container
setFragment(fragmentDemo);
(OR)
setFragment(new TestFragment1());
}
// This could be moved into an abstract BaseActivity
// class for being re-used by several instances
protected void setFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction =
fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, fragment);
fragmentTransaction.commit();
}
}
To add a fragment into a Activity or FramentActivity it requires a
Container. That container should be a "Framelayout", which can be
included in xml or else you can use the default container for that
like "android.R.id.content" to remove or replace a fragment in
Activity.
main.xml
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent" >
<!-- Framelayout to display Fragments -->
<FrameLayout
android:id="#+id/frame_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<ImageView
android:id="#+id/imagenext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_margin="16dp"
android:src="#drawable/next" />
</RelativeLayout>
After read all Answers I came up with elegant way:
public class MyActivity extends ActionBarActivity {
Fragment fragment ;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
FragmentManager fm = getSupportFragmentManager();
fragment = fm.findFragmentByTag("myFragmentTag");
if (fragment == null) {
FragmentTransaction ft = fm.beginTransaction();
fragment =new MyFragment();
ft.add(android.R.id.content,fragment,"myFragmentTag");
ft.commit();
}
}
basically you don't need to add a frameLayout as container of your fragment instead you can add straight the fragment into the android root View container
IMPORTANT: don't use replace fragment as most of the approach shown here, unless you don't mind to lose fragment variable instance state during onrecreation process.
For attaching fragment to an activity programmatically in Kotlin, you can look at the following code:
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// create fragment instance
val fragment : FragmentName = FragmentName.newInstance()
// for passing data to fragment
val bundle = Bundle()
bundle.putString("data_to_be_passed", DATA)
fragment.arguments = bundle
// check is important to prevent activity from attaching the fragment if already its attached
if (savedInstanceState == null) {
supportFragmentManager
.beginTransaction()
.add(R.id.fragment_container, fragment, "fragment_name")
.commit()
}
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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=".ui.MainActivity">
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
FragmentName.kt
class FragmentName : Fragment() {
companion object {
fun newInstance() = FragmentName()
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
// receiving the data passed from activity here
val data = arguments!!.getString("data_to_be_passed")
return view
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
}
}
If you are familiar with Extensions in Kotlin then you can even better this code by following this article.
public abstract class SingleFragmentActivity extends Activity {
public static final String FRAGMENT_TAG = "single";
private Fragment fragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null) {
fragment = onCreateFragment();
getFragmentManager().beginTransaction()
.add(android.R.id.content, fragment, FRAGMENT_TAG)
.commit();
} else {
fragment = getFragmentManager().findFragmentByTag(FRAGMENT_TAG);
}
}
public abstract Fragment onCreateFragment();
public Fragment getFragment() {
return fragment;
}
}
use
public class ViewCatalogItemActivity extends SingleFragmentActivity {
#Override
public Fragment onCreateFragment() {
return new FragmentWorkShops();
}
}
For API level 17 or higher, View.generateViewId() will solve this problem. The utility method provides a unique id that is not used in build time.
This may help you
Defining a Fragment
create xml file for fragment view fragment_abc.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="TextView" />
<Button
android:id="#+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</LinearLayout>
create fragment ABCFragment.java
import androidx.fragment.app.Fragment;
public class FooFragment extends Fragment {
// The onCreateView method is called when Fragment should create its View object hierarchy,
// either dynamically or via XML layout inflation.
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup parent, Bundle
savedInstanceState) {
// Defines the xml file for the fragment
return inflater.inflate(R.layout.fragment_abc, parent, false);
}
// This event is triggered soon after onCreateView().
// Any view setup should occur here. E.g., view lookups and attaching view listeners.
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// Setup any handles to view objects here
// EditText etFoo = (EditText) view.findViewById(R.id.etFoo);
}
}
Add frameLayout in your activity
<FrameLayout
android:id="#+id/your_placeholder"
android:layout_width="match_parent"
android:layout_height="match_parent">
now in activity, add following method
protected void setFragment() {
// Begin the transaction
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
// Replace the contents of the container with the new fragment
ft.replace(R.id.fragment_container, new ABCFragment());
// or ft.add(R.id.your_placeholder, new ABCFragment());
// Complete the changes added above
ft.commit();
}
reference : https://guides.codepath.com/android/creating-and-using-fragments#defining-a-fragment