I am trying to implement a navigation drawer. "Fragment1" is a list fragment:
public class Fragment1 extends ListFragment {
private List<String> musicList;
public static ListFragment newInstance(Context context) {
Fragment1 f = new Fragment1();
return f;
}
However i cannot use the fragmenttransaction to replace the fragments in the main activity:
public class MainActivity extends AbstractNavDrawerActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if ( savedInstanceState == null ) {
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Fragment1()).commit();
}
}
#Override
protected void onNavItemSelected(int id) {
switch ((int)id) {
case 101:
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Fragment1()).commit();
break;
case 102:
getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Fragment2()).commit();
break;
}
}
}
The replace method has a redline under it and says:
The method replace(int, Fragment) in the type FragmentTransaction is not applicable for the arguments (int, Fragment1)"
What should i do?
getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.content_frame, new Fragment1()).commit();
IMO you should avoid having such long code with method call after method code, it's messy and hard to understand! Maybe try :
FragmentTransaction transaction = getActivity().getSupportFragmentManager()
.beginTransaction();
Fragment newFragment = new Fragment1();
transaction.add(R.id.content_frame, newFragment);
transaction.addToBackStack(null);
transaction.commit();
Related
In my MainActivity class, I have a BottomNavigationView with 3 tabs that switch between activities (home, search, and personal). Whenever I click on any of the tabs, it pulls up the respective fragment, but I believe that I am calling a new fragment each and every time.
I need these fragments to maintain whatever changes are made in them (similarly to how Instagram does). Each fragment is currently very basic (newly created and unchanged), but I want to set them up in a way in which their states are saved when I switch to another fragment and restored when I go back to them.
Below is code for my main activity and the home fragment.
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
BottomNavigationView navigationView = (BottomNavigationView) findViewById(R.id.bottomNavigationView);
navigationView.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
transaction.replace(R.id.content, new HomeFragment()).commit();
}
private BottomNavigationView.OnNavigationItemSelectedListener mOnNavigationItemSelectedListener =
new BottomNavigationView.OnNavigationItemSelectedListener(){
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item){
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction transaction = fragmentManager.beginTransaction();
switch (item.getItemId()){
case R.id.HomeItem:
transaction.replace(R.id.content, new HomeFragment()).commit();
return true;
case R.id.SearchItem:
transaction.replace(R.id.content, new SearchFragment()).commit();
return true;
case R.id.PersonalItem:
transaction.replace(R.id.content, new PersonalFragment()).commit();
return true;
}
return false;
}
};
}
public class HomeFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
// TODO: Rename and change types of parameters
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public HomeFragment() {
// Required empty public constructor
}
// TODO: Rename and change types and number of parameters
public static HomeFragment newInstance(String param1, String param2) {
HomeFragment fragment = new HomeFragment();
Bundle args = new Bundle();
args.putString(ARG_PARAM1, param1);
args.putString(ARG_PARAM2, param2);
fragment.setArguments(args);
return fragment;
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
mParam1 = getArguments().getString(ARG_PARAM1);
mParam2 = getArguments().getString(ARG_PARAM2);
}
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_home, container, false);
}
// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed(Uri uri) {
if (mListener != null) {
mListener.onFragmentInteraction(uri);
}
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof OnFragmentInteractionListener) {
mListener = (OnFragmentInteractionListener) context;
} else {
Toast.makeText(context, "Home Fragment Attached", Toast.LENGTH_SHORT).show();
}
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
You must use transaction.hide(fragment) and transaction.show(fragment) instead of transaction.replace, since replacing will delete the fragment and add it again, removing its saved state.
Doing it my way will call fragments' onPause and onReaume method, not resetting their state.
Hope it helps!
I have to set the listener for a NavigationView in my main class. But the main, will containt a lot of stuff, and I want to have it the most "separated" possible.
So I will do listeners in their own java files, to something like:
navigationView.setNavigationItemSelectedListener(new NavigationListener());
The problem comes, that I have to call getSupportFragmentManager , but is not accesible, so, I suppose that I need to do something like: context.getSupportFragmentManager to make ir "work".
But I don't know how to get the context.
How can I get it?
ListenerClass:
public class NavigationListener implements NavigationView.OnNavigationItemSelectedListener {
#Override
public boolean onNavigationItemSelected(MenuItem item) {
boolean fragmentTransaction = false;
String TAG = "NavigationViewListener";
Logger.init(TAG);
Fragment fragment = null;
switch (item.getItemId()){
case R.id.nav_home:
fragment = new FragmentHome();
fragmentTransaction = true;
break;
case R.id.nav_map:
fragment = new FragmentMap();
fragmentTransaction = true;
break;
case R.id.nav_log_out:
Logger.d("Pulsada opnciĆ³n de LogOut");
break;
}
if(fragmentTransaction){
getSupportFragmentManager().beginTransaction()
.replace(R.id.main_content, fragment)
.commit();
item.setChecked(true);
getSupportActionBar().setTitle(item.getTitle());
}
}
}
You could just pass the instance of your FragmentActivity to NavigationListener as a constructor param:
public class NavigationListener implements NavigationView.OnNavigationItemSelectedListener {
FragmentActivity activity;
public NavigationListener(FragmentActivity activity) {
this.activity = activity;
}
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// ...
if(fragmentTransaction){
activity.getSupportFragmentManager().beginTransaction()
.replace(R.id.main_content, fragment)
.commit();
// ...
}
}
}
From your FragmentActivity:
navigationView.setNavigationItemSelectedListener(new NavigationListener(this));
In myfragment class witch extends Fragment I'm finding object reference in onCreateView method
private static final String TAG = "CloadLab";
private Cloud dCloud;
private EditText dNameText;
public String dNameHolder = "";
#Override
public void onCreate(Bundle savedInstanceState){
super.onCreate(savedInstanceState);
UUID dreamId = (UUID)getArguments().getSerializable(EXTRA_DREAM_ID);
}
#Override
public void onActivityCreated(#Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
getActivity().setTitle("Add new");
}
#Override
public View onCreateView(LayoutInflater inflater,
ViewGroup parent, Bundle savedInstanceState){
View v = inflater.inflate(R.layout.fragment_add,parent,false);
dNameText = (EditText) v.findViewById(R.id.dream_name);
return v;
}
public void SaveDream (){
dNameHolder = dNameText.getText().toString();
if (dNameText != null) {
Log.e(TAG,"not null");
}else if (dNameText == null){
Log.e(TAG,"null");
}
}
}
which works fine if I use it within onCreateView method, but for example I want to use dNameText in this method which is in same class
public void SaveDream (){
dNameHolder = dNameText.getText().toString();
}
and now it has null object reference how can I fix that and how can I set references through whole class?
I'm calling this SaveDream() method from Activity which holds this Fragment
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_favorite:
AddFragment mActivity= new AddFragment();
mActivity.SaveDream();
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
Every Activity extends SingleFragmentActivity and has these methods in it
private AddFragment mFragment;
#Override
protected Fragment createFragment() {
UUID dreamId = (UUID)getIntent()
.getSerializableExtra(AddFragment.EXTRA_DREAM_ID);
return AddFragment.newInstance(dreamId);
}
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
//setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.action_bar_menu,menu);
return super.onCreateOptionsMenu(menu);
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.action_favorite:
// AddFragment mActivity= new AddFragment();
// mActivity.SaveDream();
//finish();
mFragment = new AddFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, mFragment);
fragmentTransaction.commit();
mFragment.SaveDream();
finish();
return true;
}
return super.onOptionsItemSelected(item);
}
SingleFragmentActivity
protected abstract Fragment createFragment();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_fragment);
FragmentManager fm = getSupportFragmentManager();
Fragment fragment = fm.findFragmentById(R.id.fragmentContainer);
// getSupportActionBar().setDisplayHomeAsUpEnabled(false);
if (fragment == null){
fragment = createFragment();
fm.beginTransaction()
.add(R.id.fragmentContainer, fragment)
.commit();
}
}
You are calling SaveDream method on a new instance of the fragment, not the one which is loaded right now at
AddFragment mActivity= new AddFragment();
mActivity.SaveDream();
Because the view is not created on the new instance (view is created while loading) and you are getting null for EditText. You should keep the loaded instance globally and call the method on that instance.
Follow these steps.
Step 1: Create a class level variable
private AddFragment mFragment;
Step 2: Load Fragment like this
mFragment = new AddFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(android.R.id.content, mFragment);
fragmentTransaction.commit();
Step 3: Call method like this
mFragment.SaveDream();
Update
Update method like this
#Override
protected Fragment createFragment() {
UUID dreamId = (UUID)getIntent()
.getSerializableExtra(AddFragment.EXTRA_DREAM_ID);
mFragment = AddFragment.newInstance(dreamId);
return mFragment;
}
and
case R.id.action_favorite:
mFragment.SaveDream();
return true;
I have the following code for ActionBar:
private class MyTabListener implements ActionBar.TabListener
{
private Fragment mFragment;
private final Activity mActivity;
private final String mFrag;
public MyTabListener( Activity activity, String fragName )
{
mActivity = activity;
mFrag = fragName;
}
#Override
public void onTabReselected( Tab tab, FragmentTransaction ft )
{
// TODO Auto-generated method stub
}
#Override
public void onTabSelected( Tab tab, FragmentTransaction ft )
{
mFragment = Fragment.instantiate( mActivity, mFrag );
ft.add( android.R.id.content, mFragment );
}
#Override
public void onTabUnselected( Tab tab, FragmentTransaction ft )
{
ft.remove( mFragment );
mFragment = null;
}
}
I have some textboxes within those Tab fragments and switching between the tabs forces the app to lose any data I added to those textbox. Instead of add and remove, I would like to use attach and detach which saves the fragment state.
How do I accomplish that within the code that I already have?
Update:
The code now looks like this:
private class MyTabListener implements ActionBar.TabListener
{
private Fragment mFragment;
private final Activity mActivity;
private final String mFrag;
public MyTabListener( Activity activity, String fragName )
{
mActivity = activity;
mFrag = fragName;
}
#Override
public void onTabReselected( Tab tab, FragmentTransaction ft )
{
// TODO Auto-generated method stub
}
#Override
public void onTabSelected( Tab tab, FragmentTransaction ft )
{
//mFragment = Fragment.instantiate( mActivity, mFrag );
//ft.add( android.R.id.content, mFragment );
mFragment = mActivity.getSupportFragmentManager().findFragmentByTag(mFrag);
if( mFragment == null ) {
mFragment = Fragment.instantiate(mActivity, mClass.getName());
ft.add(android.R.id.content, mFragment, mFrag);
} else {
ft.attach(mFragment);
}
}
#Override
public void onTabUnselected( Tab tab, FragmentTransaction ft )
{
//ft.remove( mFragment );
//mFragment = null;
if (mFragment != null) {
ft.detach(mFragment);
}
}
}
And I am getting an error for the following line:
mFragment = mActivity.getSupportFragmentManager().findFragmentByTag(mFrag);
Error:
The method getSupportFragmentManager() is undefined for the type Activity
Instead of rewriting your code, you could just use SharedPreferences to temporarily store the variables being displayed.
In the onDestroy method of the tab you're leaving, just add your variables to the preferences, and retrieve them when you re-enter the tab.
#Override
public void onDestroy(){
super.onDestroy();
Log.i("OnDestroy", "Logged");
SharedPreferences prefs = getActivity().getSharedPreferences("name", Context.MODE_PRIVATE);
Editor editor = prefs.edit();
editor.putString("stringName", stringToStore);
editor.commit();
}
Are android fragments reusable - i mean if i could use code like below:
class MyTabActivity extends FragmentActivity implements OnClickListener {
Fragment[] tabs = new Fragment[3];
#Override
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
setContentView(R.layout.settings_activity);
findViewById(R.id.button1).setOnClickListener(this);
findViewById(R.id.button2).setOnClickListener(this);
findViewById(R.id.button3).setOnClickListener(this);
//first xml-defined fragment, it is inside
//FrameLayout with id R.id.loadTarget -> see openTab()
tabs[0] = getSupportFragmentManager().findFragmentById(
R.id.firstFragment);
}
private void openTab(int i) {
final FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.loadTarget, getTabFragment(i));
ft.addToBackStack(null);
ft.commit();
}
private Fragment getTabFragment(int i) {
if(tabs[i] == null) {
switch(i) {
//0-tab fragment has been allready
//retrieved in onCreate
case 1:
tabs[1] = new MySecondTabFragment();
break;
case 2:
tabs[2] = new MyThirdTabFragment();
break;
}
}
return tabs[i];
}
#Override
public void onClick(View v) {
switch(v.getId()) {
case R.id.button1:
openTab(0);
break;
case R.id.button2:
openTab(1);
break;
case R.id.button3:
openTab(2);
break;
}
}
}
Yes fragments are reusable you can attach/detach a fragment to an activity several times. As you can see in the documentation after being detached the fragment is destroyed and then created again when it is added to another activity.