How to maintain fragment state when switching fragments - java

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!

Related

Work with BroadcastReceiver in many fragments

I working with a PDA that has a laser scanner. For that I'm working with BroadcastReceiver in many fragment. I have one activity that has a BottomNavigationView to switch between three fragments. I'm using BroadcastReceiver like this :
package com.example.package.fragments;
public class MyFragment extends Fragment {
// TODO: Rename parameter arguments, choose names that match
// the fragment initialization parameters, e.g. ARG_ITEM_NUMBER
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;
private final static String SCAN_ACTION = "scan.rcv.message";
ScanDevice sm;
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
//Doing my work
}
};
public MyFragment () {
// Required empty public constructor
}
public static MyFragment newInstance(String param1, String param2) {
CarteGriseFragment fragment = new CarteGriseFragment();
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) {
sm = new ScanDevice();
IntentFilter filter = new IntentFilter();
filter.addAction(SCAN_ACTION);
getContext().registerReceiver(mReceiver, filter);
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.fragment_carte_grise, container, false);
return view;
}
// 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 {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void onResume() {
super.onResume();
sm = null;
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mReceiver);
}
#Override
public void onPause() {
super.onPause();
sm = null;
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mReceiver);
}
#Override
public void onDetach() {
super.onDetach();
mListener = null;
sm = null;
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mReceiver);
}
#Override
public void onDestroy() {
super.onDestroy();
sm = null;
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mReceiver);
}
#Override
public void onDestroyView() {
super.onDestroyView();
sm = null;
LocalBroadcastManager.getInstance(getActivity()).unregisterReceiver(mReceiver);
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
The problem is that, when I move to another fragment, BroadcastReceiver of the first fragment keep working in the second. In fact, when I scan something while being in the second fragment the BroadcastReceiver of the first fragment is called. I searched for many solutions, as you can see in the code above, I tried to unregister the BroadcastReceiver, but not working.
The code of the other fragment is similar to the code above.
I guess the problem is in navigation view all fragments stays in a visible state, hence onPause is not called. you can try to unsubscribe in this method setUserVisibleHint when isVisibleToUser = false
Maybe you can use RxJava.
You say "I have one activity".
Use RxJava like this.
You need to just one BroadcastReceiver in your activity.Listen it when triggered "onReceive" function then you send event with RxJava and listen this event in your fragments.

How to move one fragment to another fragment in android

I am developing an app contains fragments. I cannot move one fragment to another fragment.
When i use this code (reference from android value passing from fragment to fragment using recyclerview not working)
SpeedDialFragment fragobj = new SpeedDialFragment();
Bundle bundle=new Bundle();
bundle.putString("message", "From Activity");
fragobj.setArguments(bundle);
switchFragment(R.layout.fragment_page, fragobj);
It is not working.
My codes are shown below.
MainActivity java:
public class MainActivity extends AppCompatActivity implements PageFragment.OnFragmentInteractionListener {
ViewPager viewPage;
#Override protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
startService(new Intent(this, LockScreenService.class));
}
private void initView() {
initViewPager();
}
private void initViewPager() {
viewPage = (ViewPager) this.findViewById(R.id.viewpage);
viewPage.setOffscreenPageLimit(3);
viewPage.setCurrentItem(1);
viewPage.setAdapter(new FragmentStatePagerAdapter(getSupportFragmentManager()) {
#Override public Fragment getItem(int position) {
if (position < 2) {
return PageFragment.newInstance("", "");
} else {
return new AmapFragment();
}
}
#Override public int getCount() {
return 3;
}
});
}
#Override public void onFragmentInteraction(Uri uri) {
}
public void loadFragment(int id, Fragment fragment) {
FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
ft.replace(id, fragment, fragment.toString());
ft.addToBackStack(null);
ft.commit();
}
}
activity_main.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:id="#+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.happiness.lockscreen.MainActivity"
>
<android.support.v4.view.ViewPager
android:id="#+id/viewpage"
android:layout_width="match_parent"
android:layout_height="match_parent"
></android.support.v4.view.ViewPager>
</RelativeLayout>
fragment_page.xml
<FrameLayout 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"
>
<Button
android:text="Speed Dial"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/buttonSpeedDial" />
</FrameLayout>
PageFragment.java
public class PageFragment extends Fragment {
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
Button button;
Context context;
private OnFragmentInteractionListener mListener;
public PageFragment() {
}
public static PageFragment newInstance(String param1, String param2) {
PageFragment fragment = new PageFragment();
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
View view = inflater.inflate(R.layout.fragment_page, container, false);
button = (Button) view.findViewById(R.id.buttonSpeedDial);
button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Log.d("SpeedDialFragment", "clicked : ");
/*SpeedDialFragment fragment = new SpeedDialFragment(); // replace your custom fragment class
Bundle bundle = new Bundle();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
bundle.putString("key","value"); // use as per your need
fragment.setArguments(bundle);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.replace(viewID,fragment);
fragmentTransaction.commit();*/
SpeedDialFragment fragobj = new SpeedDialFragment();
Bundle bundle=new Bundle();
bundle.putString("message", "From Activity");
fragobj.setArguments(bundle);
switchFragment(R.layout.fragment_page, fragobj);
}
});
return view;
}
public void switchFragment(int id, Fragment fragment) {
if (context == null)
return;
if (context instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) context;
mainActivity.loadFragment(id, fragment);
}
}
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 {
throw new RuntimeException(
context.toString() + " must implement OnFragmentInteractionListener");
}
}
#Override public void onDetach() {
super.onDetach();
mListener = null;
}
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
Please help me.
SpeedDialFragment.java
public class SpeedDialFragment extends Fragment {
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public SpeedDialFragment() {
// Required empty public constructor
}
/**
* 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 PageFragment.
*/
// TODO: Rename and change types and number of parameters
public static PageFragment newInstance(String param1, String param2) {
PageFragment fragment = new PageFragment();
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) {
String strtext=getArguments().getString("message");
Log.d("SpeedDialFragment", "strtext : "+strtext);
// Inflate the layout for this fragment
return inflater.inflate(R.layout.fragment_speeddial, container, false);
}
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 {
throw new RuntimeException(
context.toString() + " must implement OnFragmentInteractionListener");
}
}
#Override public void onDetach() {
super.onDetach();
mListener = null;
}
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
if(context==null) return; You have not initialized your context object.
Try this
public void switchFragment(int id, Fragment fragment) {
if (getActivity() instanceof MainActivity) {
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.loadFragment(id, fragment);
}
}

How to set one main activity and populate fragments in android

i have one mainactivity and other fragments , what i want is that by using only that single activity , i show a default fragment in activity and then when user click on navigation drawer then fragments according to that item must populate on the same are but with different information , i had searched a lot but not got proper solution for it , i am pasting my mainactivity class here ,
public class MainActivity extends AppCompatActivity implements NavigationView.OnNavigationItemSelectedListener, FragmentOne.OnFragmentInteractionListener,
FragmentTwo.OnFragmentInteractionListener {
private ListView mDrawerList;
private String[] mNavigationDrawerItemTitles;
Toolbar toolbar;
private SliderLayout mDemoSlider;
DrawerLayout drawer;
private CharSequence mDrawerTitle;
private CharSequence mTitle;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
mTitle = mDrawerTitle = getTitle();
setSupportActionBar(toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
NavigationView navView = (NavigationView) findViewById(R.id.nav_right_view);
navView.setNavigationItemSelectedListener(this);
navView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle Right navigation view item clicks here.
int id = item.getItemId();
Fragment fragment = null;
Class fragmentClass = null;
if (id == R.id.nav_settings) {
fragmentClass = first.class;
} else if (id == R.id.nav_logout) {
fragmentClass = secnd.class;
} try {
fragment = (Fragment) fragmentClass.newInstance();
} catch (Exception e) {
e.printStackTrace();
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();
item.setChecked(true);
setTitle(item.getTitle());
DrawerLayout mDrawer = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawer.closeDrawers();
return true;
}
});
}
code for first fragment class is here ,
public class first extends Fragment {
private static final String ARG_PARAM1 = "param1";
private static final String ARG_PARAM2 = "param2";
private String mParam1;
private String mParam2;
private OnFragmentInteractionListener mListener;
public first() {
// Required empty public constructor
}
/**
* 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 FragmentOne.
*/
// TODO: Rename and change types and number of parameters
public static first newInstance(String param1, String param2) {
FragmentOne fragment = new FragmentOne();
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_fragment_one, 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 {
throw new RuntimeException(context.toString()
+ " must implement OnFragmentInteractionListener");
}
}
#Override
public void 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.
* <p/>
* See the Android Training lesson <a href=
* "http://developer.android.com/training/basics/fragments/communicating.html"
* >Communicating with Other Fragments</a> for more information.
*/
public interface OnFragmentInteractionListener {
// TODO: Update argument type and name
void onFragmentInteraction(Uri uri);
}
}
Thanks in advance
For solving your problem i am just using your code and doing some improvments ,just use required code in your activity file .
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
mTitle = mDrawerTitle = getTitle();
setSupportActionBar(toolbar);
///it is required code
if (savedInstanceState == null) {
Fragment fragment = null;
Class fragmentClass = null;
fragment = new Fragmentforslider();
fragmentClass= FragmentOne.class;
try {
} catch (Exception e) {
e.printStackTrace();
}
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.beginTransaction().replace(R.id.flContent, fragment).commit();
}
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);

EditText becomes null on other methods

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;

getActivity in Fragment is null after change of orientation (single and one pane layout)

I have a problem and the solutions I've found did not work for me (check for null etc.).
I have a simple activity which hosts 2 fragments in landscape mode and 1 framelayout in portrait mode. When I change the orientation of the device and then change it back, the click handler is not working (getActivity() in DetailFragment is null).
Here is my code so far:
//UserListActivity.java
public class UserListActivity extends AppCompatActivity implements UserListFragment.OnUserListSelectedListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_user_list);
// Check whether the activity is using the layout version with
// the fragment_container FrameLayout. If so, we must add the first fragment
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
UserListFragment fragment = new UserListFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container, fragment, "");
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.commit();
}
}
#Override
public void onUserListSelected(User selectedUser) {
UserDetailFragment userDetailFragment = (UserDetailFragment) getSupportFragmentManager().findFragmentById(R.id.user_detail_fragment);
if (userDetailFragment != null) {
// If detail frag is available, we're in two-pane layout...
userDetailFragment.updateSelectedView(selectedUser);
} else {
// Otherwise, we're in the one-pane layout and must swap frags...
//create detailFragment
UserDetailFragment newFragment = new UserDetailFragment();
Bundle args = new Bundle();
args.putString(UserDetailFragment.ARG_SELECTED_USER, new Gson().toJson(selectedUser));
newFragment.setArguments(args);
//replace fragment
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, newFragment, "");
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
}
//UserListFragment.java
public class UserListFragment extends ListFragment implements AdapterView.OnItemClickListener {
private OnUserListSelectedListener mCallback;
private User[] users;
public interface OnUserListSelectedListener {
void onUserListSelected(User selectedUser);
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
return inflater.inflate(R.layout.user_list_fragment, container, false);
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if (users == null) {
getAllUsers();
} else {
setAdapter();
}
getListView().setOnItemClickListener(this);
}
#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 = (OnUserListSelectedListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnUserListSelectedListener");
}
}
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
mCallback.onUserListSelected(users[position]);
}
private void setAdapter() {
setListAdapter(new UserListAdapter(getActivity(), R.layout.user_list_row, users));
}
private void getAllUsers() {
try {
//...
//Async webCall using volley
//...
users = tmp.getUsers().toArray(new User[tmp.getUsers().size()]);
setAdapter();
//...
}
}
//UserDetailFragment.java
public class UserDetailFragment extends Fragment {
final public static String ARG_SELECTED_USER = "selectedUser";
private User mSelectedUser;
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
if (savedInstanceState != null) {
mSelectedUser = new Gson().fromJson(savedInstanceState.getString(ARG_SELECTED_USER), User.class);
}
return inflater.inflate(R.layout.user_detail_fragment, container, false);
}
#Override
public void onStart() {
super.onStart();
Bundle args = getArguments();
if (args != null) {
updateSelectedView(new Gson().fromJson(args.getString(ARG_SELECTED_USER), User.class));
} else {
updateSelectedView(null);
}
}
#Override
public void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
outState.putString(ARG_SELECTED_USER, new Gson().toJson(mSelectedUser));
}
public void updateSelectedView(User selectedUser) {
//??? WHY IS GETACTIVITY() AFTER CHANGE OF ORIENTATION NULL ???
if (getActivity() != null) {
TextView textUserName = (TextView) getActivity().findViewById(R.id.textUserName);
TextView textUserEmail = (TextView) getActivity().findViewById(R.id.textUserEmail);
if (selectedUser != null) {
textUserName.setText(selectedUser.getName());
textUserEmail.setText(selectedUser.getEmail());
mSelectedUser = selectedUser;
} else {
textUserName.setText(null);
}
}
}
}
UserDetailFragment userDetailFragment = (UserDetailFragment) getSupportFragmentManager().findFragmentById(R.id.user_detail_fragment);
Creates a new instance of fragment.
if (findViewById(R.id.fragment_container) != null) {
// However, if we're being restored from a previous state,
// then we don't need to do anything and should return or else
// we could end up with overlapping fragments.
if (savedInstanceState != null) {
return;
}
UserListFragment fragment = new UserListFragment();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.add(R.id.fragment_container, fragment, "");
fragmentTransaction.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN);
fragmentTransaction.commit();
}
is reusing the old instance of fragment .
Therefore, use getFragmentByTag() and dont keep the tag empty string (""), while calling .add

Categories

Resources