I am trying to create a tablet application with fragments. The left part of the screen will have four buttons and the right part of the screen will change depending on what button was clicked.
I have created main activity and four fragments. Each fragment has its own layout with several TextView fields. When applications starts it loads all fragments to RAM - this way it can keep the fragments status so that when user switch from one fragment to another all the text fields keep their text values until he clicks the final submit button. The app is based on SDK 4.1. The app is a little bit slow especially when it starts. I was wondering if it has been designed properly and if there are some way to improve it?
Below is the main activity class:
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.Menu;
import android.view.View;
import android.widget.Button;
public class MainActivity extends Activity {
private Button buttonOne;
private Button buttonTwo;
private Button buttonThree;
private Button buttonFour;
private Fragment fragmentOne;
private Fragment fragmentTwo;
private Fragment fragmentThree;
private Fragment fragmentFour;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
buttonOne = (Button) findViewById(R.id.button_one);
buttonTwo = (Button) findViewById(R.id.button_two);
buttonThree = (Button) findViewById(R.id.button_three);
buttonFour = (Button) findViewById(R.id.button_four);
fragmentOne = new FragmentOne();
fragmentTwo = new FragmentTwo();
fragmentThree = new FragmentThree();
fragmentFour = new FragmentFour();
FragmentTransaction fragmentTransaction = getFragmentManager()
.beginTransaction();
fragmentTransaction.add(R.id.frameLayout_one, fragmentOne);
fragmentTransaction.add(R.id.frameLayout_one, fragmentTwo);
fragmentTransaction.add(R.id.frameLayout_one, fragmentThree);
fragmentTransaction.add(R.id.frameLayout_one, fragmentFour);
fragmentTransaction.commit();
buttonOne.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
FragmentTransaction fragmentTransaction = getFragmentManager()
.beginTransaction();
fragmentTransaction.show(fragmentOne);
fragmentTransaction.hide(fragmentTwo);
fragmentTransaction.hide(fragmentThree);
fragmentTransaction.hide(fragmentFour);
fragmentTransaction.commit();
}
});
buttonTwo.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
FragmentTransaction fragmentTransaction = getFragmentManager()
.beginTransaction();
fragmentTransaction.hide(fragmentOne);
fragmentTransaction.show(fragmentTwo);
fragmentTransaction.hide(fragmentThree);
fragmentTransaction.hide(fragmentFour);
fragmentTransaction.commit();
}
});
buttonThree.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
FragmentTransaction fragmentTransaction = getFragmentManager()
.beginTransaction();
fragmentTransaction.hide(fragmentOne);
fragmentTransaction.hide(fragmentTwo);
fragmentTransaction.show(fragmentThree);
fragmentTransaction.hide(fragmentFour);
fragmentTransaction.commit();
}
});
buttonFour.setOnClickListener(new View.OnClickListener() {
public void onClick(View view) {
FragmentTransaction fragmentTransaction = getFragmentManager()
.beginTransaction();
fragmentTransaction.hide(fragmentOne);
fragmentTransaction.hide(fragmentTwo);
fragmentTransaction.hide(fragmentThree);
fragmentTransaction.show(fragmentFour);
fragmentTransaction.commit();
}
});
}
Consider using a FragmentStateViewPager.
In an ideal world, if you have several Fragments you are switching between like in your case, you'll probably not want to keep them around in RAM. 2 or 3 fragments is probably okay, 4 or more is starting to push it.
The FragmentStateViewPager will automatically detach and save the state of your Fragments as they move "off screen"
You will have to implement onSaveInstanceState in each one of your fragments to save any state of any non-UI member variables (UI Views save their state automagically). Then restore them in onCreate or onCreateView.
*Of course, if your Fragments' onCreate/onCreateViews are slow, then this won't help much. First make sure your Fragments' creations are fast... Start by looking for code that can be moved from onCreate/onCreate view to onResume.
Related
I thought that calls to a fragment were synchronous but it's not. I have a fragment 1 that contains a listview that I update through an adapter. Then I have a button that launches fragment 2. Frag2 has an effect on the listview of frag1 so I thought I could do as follows below. But when I click on button btn1 my fragment frag2 is launched and immediately after I see the log.i.
I would like to avoid a refresh button in frag1.
Is there a way to do an action right after frag2 has ended?
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
context = getActivity().getApplicationContext();
initFindView();
btn1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
FragmentTransaction ft = getFragmentManager().beginTransaction();
Frag2 f2 = new Frag2();
ft.replace(R.id.content_frame, f2);
ft.addToBackStack(null);
ft.commit();
Log.i("TEST","Test - back from tst2");
}
});
}
By your question, you look to only need the result, you can achieve it trough startActivity(ForResult) or with Fragments trough ResultReceiver that is a Parcelable that you can use as argument, and wait for the result to update your Frag1.
I need help with code snippet for replacing a fragment with another fragment on click of a button.
Here is the XML for the MainActivity
What can i do to resolve this error?
Tried searching the web only to come up with the same solution.
If somebody could please help me out on this.
Code for Main.Activity
public class MainActivity extends AppCompatActivity{
Button button1, button2, button3, button4;
Fragment fragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
button1=(Button)findViewById(R.id.layout1);
button2=(Button)findViewById(R.id.layout2);
button3=(Button)findViewById(R.id.layout3);
button4=(Button)findViewById(R.id.layout4);
button1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
fragment = new Fragment2();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.frag, fragment);
transaction.commit();
}
});
I saw few issues in your code:
If you add your fragment inside xml file, you cant remove/replace it in the future. As described from Google Page:
Note: When you add a fragment to an activity layout by defining the fragment in the layout XML file, you cannot remove the fragment at runtime. If you plan to swap your fragments in and out during user interaction, you must add the fragment to the activity when the activity first starts, as shown in the next lesson.
Your error may come from casting fragment. You should check your Fragment2. it maybe a support fragment.
Update
Here's the link to learning more about creating/adding fragment: Google Guide
Based on your comments, you should check what you did import in the Fragment2 layout (import android.support.v4.app.Fragment; or not). Are all your fragments from the same package or not?
The variable 'fragment' is an object of class Fragment and you are creating it as a object of class Fragment2 (which is a subclass of Fragment). This is not valid hence it's showing an error. Also to replace any fragment the fragment it should be inside a container view (usually a FrameLayout) and then you can use the replace transaction to replace it on the button click. The code should be as follows:
XML Code:
<FrameLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="frameLayout" />
Java Code:
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
FragmentManager fm = getSupportFragmentManager();
fm.beginTransaction().replace(R.id.frameLayout,fragment2).commit();
}
});
Just replace your fragment in your xml with a FrameLayout.
Now within button's onClickListener
YourFragment fragment = YourFragment.getInstance();
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.frLayout, fragment, "TAG");
transaction.commit();
Hope that helps.
You should try
<FrameLayout
android:id="#+id/frameLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
/>
in xml insted of fragment
and try this
Fragment2 frag2 = new Fragment2();
getSupportFragmentManager().beginTransaction().replace(R.id.frag, frag2);
in java code.
I have a Main Menu and created a fragment and its layout.
Now I can't seems to start fragment when user presses a button on main menu.
main menu has its own layout.
now is there anyway i could initialize it from a button?
Button bt = (Button)findViewById(R.id.button1);
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(MainMenu.this, ExercisesFragment.class));
}
});
}
I tried it by this but it gives error saying
Fragment cannot be cast to android.app.Activity
You add fragments using fragment manager:
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ExercisesFragment fragment = new ExercisesFragment();
fragmentTransaction.replace(R.id.fragment_container, fragment);
fragmentTransaction.commit();
read more on fragments, start here:
http://developer.android.com/guide/components/fragments.html
FragmentTransaction ft = activity.getSupportFragmentManager().beginTransaction();
ft.add(R.id.main_fragment, your_fragment);
ft.addToBackStack("ifneeded");
ft.commit();
You are doing it wrong! Intents are not used to load a fragment.
Solution is to use fragment transactions
to dynamically load the fragment you wish to bring into focus.
Here is what you need to do:
Have a container for the fragment inside the layout of you activity
Example: Assuming the layout resource of my activity is activity_main.xml, I would have a container like so
Follow this guide to create a Fragment
Assuming you already have a fragment setup with name AbcFragment, use fragment transactions to load the fragment into the container that you just created, whenever the user clicks on the button:
bt.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
getFragmentManager()
.beginTransaction()
.replace(R.id.fragment-container, new AbcFragment)
.commit();
}
});
i am designing an alarm application.
I am working with a fragment that acts as my alarms, the idea is to use the same one for each new alarm (i don't know if this is the right way).
Well, then i am basically trying to add, via pressing a "new alarm" button, the same fragment again into the layout of an activity, but when i press the button the app crashes. Any help?
I am inserting the fragment into a LinearLayout that is inside a ScrollView that is inside of the RelativeLayout
package com.example.roo.proyi;
import android.app.Fragment;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.support.v4.app.FragmentActivity;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.Button;
public class alarms extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarms);
android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
final android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
alarm_fragment alarmFragment = new alarm_fragment();
fragmentTransaction.add(R.id.alarmListContainer,alarmFragment);
fragmentTransaction.commit();
Button button_newAlarm = (Button)findViewById(R.id.button_new_alarm);
button_newAlarm.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v) {
alarm_fragment alarmFragment2 = new alarm_fragment();
fragmentTransaction.add(R.id.alarmListContainer,alarmFragment2);
fragmentTransaction.commit();
}
;
}
);
.
.
.
.
.
.CONTINUES BUT IT IS IRRELEVANT
.
.
.
FINAL SOLUTION MADE BY CREATING A DIFFERENT FRAGMENTTRANSACTION
public class alarms extends FragmentActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_alarms);
final android.support.v4.app.FragmentManager fragmentManager = getSupportFragmentManager();
final android.support.v4.app.FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
final alarm_fragment alarmFragment = new alarm_fragment();
fragmentTransaction.add(R.id.alarmListContainer,alarmFragment);
fragmentTransaction.commit();
Button button_newAlarm = (Button)findViewById(R.id.button_new_alarm);
button_newAlarm.setOnClickListener(
new Button.OnClickListener() {
public void onClick(View v) {
android.support.v4.app.FragmentTransaction fragmentTransaction2 = fragmentManager.beginTransaction();
getSupportFragmentManager().beginTransaction();
alarm_fragment alarmFragment2 = new alarm_fragment();
fragmentTransaction2.add(R.id.alarmListContainer,alarmFragment2);
fragmentTransaction2.commit();
}
;
}
);
You cannot use the same FragmentTransaction to add the fragment inside of your OnClickListener. Once you call commit() on a transaction, you cannot use it again. Call getSupportFragmentManager().beginTransaction() to get a new transaction.
Check this code out -
1. It checks whether you have added a dialog fragment in the stack already or not. If yes, it will remove the fragment and add new fragment with a new argument, if it does not exist, it will add the fragment anyway.
see if you could incorporate this approach in your code -
void showDialog() {
mStackLevel++;
// DialogFragment.show() will take care of adding the fragment
// in a transaction. We also want to remove any currently showing
// dialog, so make our own transaction and take care of that here.
FragmentTransaction ft = getFragmentManager().beginTransaction();
Fragment prev = getFragmentManager().findFragmentByTag("dialog");
if (prev != null) {
ft.remove(prev);
}
ft.addToBackStack(null);
// Create and show the dialog.
DialogFragment newFragment = MyDialogFragment.newInstance(mStackLevel);
newFragment.show(ft, "dialog");
}
Source is Android developer site
How to implement show and hide fragment inside fragment in Android? I have added two fragment inside activity. One fragment containing menu and one fragment contain sub menu. I have lot of button in menu fragment like home, idea, etc. If i click idea button. I have to show sub menu. If I again click idea button, I have to hide the sub menu. Can anybody provide example, or how to access one view fragment in another fragment?
this is my layout main
?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<fragment class="com.gcm.fragment.CommonFragment"
android:id="#+id/the_frag"
android:layout_width="wrap_content"
android:layout_height="match_parent" />
<fragment class="com.gcm.fragment.SubFragment"
android:id="#+id/the_frag1"
android:layout_marginTop="130dip"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
In My fragment
package com.gcm.fragment;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.View.OnClickListener;
import android.widget.TextView;
public class CommonFragment extends Fragment implements OnClickListener {
TextView txtIhaveIdea=null;
boolean menuVisible=false;
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
ViewGroup layout = (ViewGroup) inflater.inflate(R.layout.collapsed_menu2, container, false);
txtIhaveIdea=(TextView)layout.findViewById(R.id.txtIhaveAnIdea);
txtIhaveIdea.setOnClickListener(this);
return layout;
}
#Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(!menuVisible)
{
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fm.beginTransaction();
Fragment fragOne = new SubFragment();
ft.show(fragOne);
}
else
{
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fm.beginTransaction();
Fragment fragOne = new SubFragment();
ft.hide(fragOne);
}
}
}
Thanks
You could try get framelayout or fragment by id and change its visibility
View frag = findViewById(R.id.my_fragment);
frag.setVisibility(View.VISIBLE);
Considering this question has over 2K .. an answer may still help new readers so here it goes:
You don't really want to have FragmentManager and FragmentTransactions happening inside fragments not to have Casts nor potential harmful references to your Activity(s)
So what I do and works just fine is set an interface to the Fragment and give a method, say needsHide():
public class MyFrag extends Fragment {
public interface MyFragInterface {
public void needsHide();
}
Then implement it on your Activity:
public class MainActivity extends FragmentActivity implements MyFrag.MyFragInterface {
public void needsHide() {
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
//find the fragment by View or Tag
MyFrag myFrag = (MyFrag)fragmentManager.findFragmentByTag(SOME_TAG);
fragmentTransaction.hide(myFrag);
fragmentTransaction.commit();
//do more if you must
}}
The only part that requires thought is when to call needsHide(), this you might do in your Fragment's onViewCreated, since you are sure that it's not too early for your MainActivity to commit transactions. If you place it onCreate() it may not work depending on what you do with oter fragments:
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
// Making sure Main activity implemented interface
try {
if (USE_A_CONDITION) {
((MyFragInterface)this.getActivity()).needsHide();
}
} catch (ClassCastException e) {
throw new ClassCastException("Calling activity must implement MyFragInterface");
}
super.onViewCreated(view, savedInstanceState);
}
Simply, create a public method in your "parent" activity. which hides the fragment.
Then from within the fragment in your click event get the "parent|' activity, cast it and then call the method you created.
((ParentActitity)getActivity()).hideFragment();
You need to use an Interface to communicate with your parent Activity.
Take a look on Vogella's tutorial, "3.4. Application communication with Fragments". Here is the link
method hide():Hides an existing fragment. This is only relevant for fragments whose views have been added to a container, as this will cause the view to be hidden.
your code :
#Override
public void onClick(View v) {
if(!menuVisible)
{
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fm.beginTransaction();
Fragment fragOne = new SubFragment();
ft.show(fragOne);
}
else
{
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
fm.beginTransaction();
// it's wrong , you just hide the fragment that not added to FragmentTransaction
Fragment fragOne = new SubFragment();
ft.hide(fragOne);
}
}
Below code worked for me..
View frag = findViewById(R.id.fragment);
frag.setVisibility(View.GONE);//Or View.INVISBLE