In my application I'm using BottomBar Menu's. When quickly selecting menu's I'm getting following crash report on crashlytics(only in some devices). Here is the stacktrace
Non-fatal Exception: java.lang.IllegalStateException: Can not perform
this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1842)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1860)
at android.support.v4.app.FragmentManagerImpl.popBackStack(FragmentManager.java:781)
at com.beco.ibeco.app.MainActivity$1.onMenuTabSelected(MainActivity.java:87)
at com.beco.ibeco.app.views.bottombar.BottomBar.notifyMenuListener(BottomBar.java:1239)
at com.beco.ibeco.app.views.bottombar.BottomBar.updateSelectedTab(BottomBar.java:1199)
at com.beco.ibeco.app.views.bottombar.BottomBar.handleClick(BottomBar.java:1161)
at com.beco.ibeco.app.views.bottombar.BottomBar.onClick(BottomBar.java:1149)
at android.view.View.performClick(View.java:5076)
at android.view.View$PerformClick.run(View.java:20279)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5930)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1405)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1200)
And here is the code
protected void onCreate(Bundle savedInstanceState) {
mActive = true;
super.onCreate(savedInstanceState);
initBottomBar(savedInstanceState);
Intent intent = getIntent();
}
private void initBottomBar(Bundle savedInstanceState) {
mBottomBar = BottomBar.attach(this, savedInstanceState);
mBottomBar.useFixedMode();
mBottomBar.noTabletGoodness();
mBottomBar.setItemsFromMenu(R.menu.bottombar_menu, new OnMenuTabClickListener() {
#Override
public void onMenuTabSelected(#IdRes int menuItemId) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);//line 87
switch (menuItemId) {
case R.id.bottomBarHome:
showStoreList();
break;
case R.id.bottomBarMap:
showMap();
break;
case R.id.bottomBarDeal:
showDeals();
break;
case R.id.bottomBarSettings:
showSettings();
break;
case R.id.bottomBarNotification:
if (mNotificationBadge != null) {
mNotificationBadge.hide();
Beco.getApp().clearBadge();
}
showNotifications();
break;
}
}
#Override
public void onMenuTabReSelected(#IdRes int menuItemId) {
switch (menuItemId) {
case R.id.bottomBarHome:
if (mCurrentTab != HOME)
showStoreList();
break;
case R.id.bottomBarMap:
if (mCurrentTab != MAP)
showMap();
break;
case R.id.bottomBarDeal:
if (mCurrentTab != DEAL)
showDeals();
break;
case R.id.bottomBarNotification:
if(mCurrentTab != NOTIFICATION) {
if (mNotificationBadge != null) {
mNotificationBadge.hide();
mNotificationBadge.setDealItemCount(0);
Beco.getApp().clearBadge();
}
showNotifications();
}
break;
case R.id.bottomBarSettings:
if (mCurrentTab != SETTINGS)
showSettings();
break;
}
}
});
mNotificationBadge = mBottomBar.makeBadgeForTabAt(3, R.color.beco_badge_color, Beco.getApp().getBadgeCount());
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mBottomBar.onSaveInstanceState(outState);
}
How can I override this issue ?
Create a boolean and check if activity is not going to onpause
#Override
public void onResume() {
super.onResume();
mIsResumed = true;
}
#Override
public void onPause() {
mIsResumed = false;
super.onPause();
}
then while loading fragment check
if(mIsResumed){
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);//line 8
}
Related
I am trying to create a form using fragments in a viewpager which is a step by step process.
there are 6 fragments in the viewpager. a "Back" button and a "Next" button(in the activity).
I want to save the form when the user clicks the "Next" button.
To the Reference here is the code
The Adapter to load the Fragments
public class RegistrationPagerAdapter extends FragmentPagerAdapter {
Fragment fragment;
public RegistrationPagerAdapter(#NonNull FragmentManager fm, int behavior) {
super(fm, behavior);
}
#NonNull
#Override
public Fragment getItem(int position) {
switch (position){
case 0:
fragment = new PersonalDetailsFragment();
break;
case 1:
fragment = new AboutMeFragment();
break;
case 2:
fragment = new HoroscopeFragment();
break;
case 3:
fragment = new EducationFragment();
break;
case 4:
fragment = new FamilyFragment();
break;
case 5:
fragment = new ExpectationFragment();
break;
}
return fragment;
}
#Override
public int getCount() {
return 6;
}
#Override
public int getItemPosition(#NonNull Object object) {
return POSITION_NONE;
}
}
There are two buttons in the activity(not in fragments)
public class FormActivity extends AppCompatActivity implements View.OnClickListener {
private static final String TAG = "FormActivity";
AppCompatButton backButton, nextButton;
CustomViewPager viewpager;
Toolbar toolbar;
ApiInterface apiInterface;
RegistrationPagerAdapter adapter;
int status;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_form);
initilizeToolbar();
}
#Override
protected void onRestart() {
super.onRestart();
}
private void initilizeToolbar() {
apiInterface = ApiClient.getClient(getApplicationContext()).create(ApiInterface.class);
toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
if (getSupportActionBar() != null) {
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayShowHomeEnabled(true);
}
castComponents();
}
private void castComponents() {
viewpager = findViewById(R.id.viewPager);
backButton = findViewById(R.id.backButton);
nextButton = findViewById(R.id.nextButton);
nextButton.setOnClickListener(this);
backButton.setOnClickListener(this);
GetAllDetailsOfUser();
}
#Override
public void onResume() {
initilizeToolbar();
super.onResume();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
return super.onCreateOptionsMenu(menu);
}
public void setViewPagerData(int status) {
FragmentManager fm = getSupportFragmentManager();
adapter = new RegistrationPagerAdapter(fm, 0);
viewpager.setAdapter(adapter);
viewpager.setCurrentItem(status);
viewpager.setPagingEnabled(false);
}
public void GetAllDetailsOfUser() {
Call<AllProfileDetails> allDetails = apiInterface.allDetails(PrefUtils.getToken(this), PrefUtils.getID(this));
allDetails.enqueue(new Callback<AllProfileDetails>() {
#Override
public void onResponse(Call<AllProfileDetails> call, Response<AllProfileDetails> response) {
AllProfileDetails all = response.body();
if (all != null) {
if (all.getStatus()) {
Data data = all.getData();
setViewPagerData(data.getProfileCurrentStatus());
status = data.getProfileCurrentStatus();
}
}
}
public void onFailure(Call<AllProfileDetails> call, Throwable t) {
Crashlytics.log(t.getLocalizedMessage());
}
});
}
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.backButton:
if (viewpager.getCurrentItem() == 0){
}else{
viewpager.setCurrentItem(viewpager.getCurrentItem() - 1);
}
break;
case R.id.nextButton:
if (viewpager.getCurrentItem() == 6){
}else{
viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);
}
break;
}
}
}
this is Code is Fine but here is the problem...
When i save the data in Fragment1 i.e "PersonalDetailsFragment", it moves to fragment2 i.e "AboutMeFragment"
again when i click on save button for "AboutMeFragment" it runs the method of "PersonalDetailsFragment" only
please note that i call the activity buttons in fragments as
getActivity().findViewById(R.id.backButton);
getActivity().findViewById(R.id.nextButton);
You should have a interface like OnSaveTapped.
public interface OnSaveTapped{
void onSaveTapped();
}
Then make the fragments implement the interface above, ex:
public class PersonalDetailsFragment extends Fragment implements OnSaveTapped{
public void onSaveTapped(){
//do your business code here to save data
}
}
Finally ,In the activity class:
#Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.backButton:
if (viewpager.getCurrentItem() == 0){
}else{
viewpager.setCurrentItem(viewpager.getCurrentItem() - 1);
}
break;
case R.id.nextButton:
if (viewpager.getCurrentItem() == 6){
}else{
viewpager.setCurrentItem(viewpager.getCurrentItem() + 1);
}
break;
case R.id.button_save:
((OnSaveTapped)viewpager.getCurrentFragment()).onSaveTapped();
}
Don't forget to create new method named getCurrentFragment() to return current item (fragment) in RegistrationPagerAdapter.
public class RegistrationPagerAdapter extends FragmentPagerAdapter {
private Fragment fragment;
/**other lines of code*/
public Fragment getCurrentFragment(){
return fragment;
}
}
I'm using BottomBar menu's in my android application. And there are 5 menus in the BottomBar. This is the main activity
public class MainActivity extends BaseActivity {
private static final String TAG = "MainActivity";
private static final String COMMAND_RESET_PASSWORD = "reset-password";
private static final String COMMAND_REFERRAL = "referral";
private static final int HOME = 0;
private static final int MAP = 1;
private static final int DEAL = 2;
private static final int NOTIFICATION = 3;
private static final int SETTINGS = 4;
private BottomBar mBottomBar;
private int mCurrentTab = HOME;
private BottomBarBadge mNotificationBadge;
private boolean mActive;
#Override
protected void onCreate(Bundle savedInstanceState) {
mActive = true;
super.onCreate(savedInstanceState);
initBottomBar(savedInstanceState);
Intent intent = getIntent();
handleIntent(intent);
}
private void initBottomBar(Bundle savedInstanceState) {
mBottomBar = BottomBar.attach(this, savedInstanceState);
mBottomBar.useFixedMode();
mBottomBar.noTabletGoodness();
mBottomBar.setItemsFromMenu(R.menu.bottombar_menu, new OnMenuTabClickListener() {
#Override
public void onMenuTabSelected(#IdRes int menuItemId) {
FragmentManager fragmentManager = getSupportFragmentManager();
fragmentManager.popBackStack(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
switch (menuItemId) {
case R.id.bottomBarHome:
showStoreList();
break;
case R.id.bottomBarMap:
showMap();
break;
case R.id.bottomBarDeal:
showDeals();
break;
case R.id.bottomBarSettings:
showSettings();
break;
case R.id.bottomBarNotification:
if (mNotificationBadge != null) {
mNotificationBadge.hide();
Sample.getApp().clearBadge();
}
showNotifications();
break;
}
}
#Override
public void onMenuTabReSelected(#IdRes int menuItemId) {
switch (menuItemId) {
case R.id.bottomBarHome:
if (mCurrentTab != HOME)
showStoreList();
break;
case R.id.bottomBarMap:
if (mCurrentTab != MAP)
showMap();
break;
case R.id.bottomBarDeal:
if (mCurrentTab != DEAL) {
showDeals();
}
break;
case R.id.bottomBarNotification:
if(mCurrentTab != NOTIFICATION) {
if (mNotificationBadge != null) {
mNotificationBadge.hide();
mNotificationBadge.setDealItemCount(0);
Sample.getApp().clearBadge();
}
showNotifications();
}
break;
case R.id.bottomBarSettings:
if (mCurrentTab != SETTINGS)
showSettings();
break;
}
}
});
mNotificationBadge = mBottomBar.makeBadgeForTabAt(3, R.color.sample_badge_color, Sample.getApp().getBadgeCount());
}
public void hideBottomBar() {
if (mBottomBar != null) mBottomBar.hide();
}
public void showBottomBar() {
if (mBottomBar != null) mBottomBar.show();
}
#Override
protected void onResume() {
super.onResume();
handleCommands();
if (mNotificationBadge != null) {
mNotificationBadge.setDealItemCount(Sample.getApp().getBadgeCount());
}
}
public void showPointPopUp() {
PointDialogFragment fragment = new PointDialogFragment();
fragment.setShowsDialog(true);
fragment.show(getSupportFragmentManager(),TAG);
}
private void showStoreList() {
mCurrentTab = HOME;
Fragment fragment = Fragment.instantiate(this, StoreListFragment.class.getName());
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment)
.commitAllowingStateLoss();
}
private void showMap() {
String storeId = Sample.getApp().getMallId();
Store store = mStoreCache.getMall(storeId);
if (store != null && store.isMapAvailable()) {
Bundle args = new Bundle();
args.putString(Sample.EXTRA_STORE_ID, Sample.getApp().getMallId());
args.putBoolean(Sample.EXTRA_COMMAND, true);
Fragment fragment = Fragment.instantiate(this, SampleMapFragment.class.getName(), args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment)
.commitAllowingStateLoss();
} else {
Fragment fragment = Fragment.instantiate(this, StoreMapFragment.class.getName());
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment)
.commitAllowingStateLoss();
}
mCurrentTab = MAP;
}
private void showDeals() {
mCurrentTab = DEAL;
String storeId = Sample.getApp().getMallId();
Bundle args = new Bundle();
if (storeId != null)
args.putString(Sample.EXTRA_STORE_ID, storeId);
Fragment fragment = Fragment.instantiate(this, DealsFragment.class.getName(), args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment)
.commitAllowingStateLoss();
}
private void showNotifications(){
mCurrentTab = NOTIFICATION;
Fragment fragment = Fragment.instantiate(this, NotificationFragment.class.getName());
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment)
.commitAllowingStateLoss();
}
private void showSettings() {
mCurrentTab = SETTINGS;
Fragment fragment = Fragment.instantiate(this, ProfileFragment.class.getName());
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment)
.commitAllowingStateLoss();
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
protected int getLayoutResource() {
return R.layout.activity_content_frame;
}
#Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
setIntent(intent);
Log.d(TAG, "inside onNewIntent");
if (mActive) {
handleIntent(getIntent());
}
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
mBottomBar.onSaveInstanceState(outState);
}
#Override
protected void onDestroy() {
mActive = false;
super.onDestroy();
}
#Override
protected void onStart() {
super.onStart();
Branch branch = Branch.getInstance();
if (BuildConfig.DEBUG) {
branch.setDebug();
}
Log.d(TAG, "inside branch no error");
branch.initSession((referringParams, error) -> {
if (error == null) {
try {
Log.d(TAG, "parsed data from referringParams");
if (referringParams.has("data")) {
String link = referringParams.getJSONObject("data").getString("link");
if(link != null && !link.isEmpty()){
Uri uri = Uri.parse(link);
if(uri.getScheme().equals("sample")){
List<String> pathSegments = uri.getPathSegments();
String command = "";
String argument = null;
if (!pathSegments.isEmpty() && pathSegments.size() == 1) {
command = uri.getHost();
argument = pathSegments.get(0);
}
if(COMMAND_REFERRAL.equals(command) && argument != null){
Sample.getApp().currentUser().setReferralCode(argument);
}else {
Intent activityIntent = new Intent(MainActivity.this, LinkHandlerActivity.class);
activityIntent.setData(uri);
startActivity(activityIntent);
}
}
}
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, this.getIntent().getData(), this);
}
public void showSignUpInPage() {/*line 319 */
Bundle args = new Bundle();
args.putString(Sample.TYPE, Sample.SIGN_UP);
Fragment fragment =
Fragment.instantiate(this, SignUpInFragmentMain.class.getName(),args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment)
.addToBackStack(null)
.commit();/***This is the 319th line***/
}
public void forgotPassword(){
Fragment fragment =
Fragment.instantiate(this, ForgotPasswordFragment.class.getName());
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment)
.addToBackStack(null)
.commit();
}
private void handleCommands() {
if (!mActive || Sample.getApp().getNotificationCommand() == null) {
return;
}
switch (Sample.getApp().getNotificationCommand()) {
case Sample.COMMAND_DEAL:
showStoreDetail(Sample.getApp().getStoreId());
break;
case Sample.COMMAND_MALL_DEAL:
showMallDetail(Sample.getApp().getStoreId());
break;
case Sample.COMMAND_REGISTER:
showSignUpInPage();
break;
case Sample.COMMAND_DEFAULT:
break;
case Sample.COMMAND_MAP:
mBottomBar.selectTabAtPosition(1, true);
break;
}
Sample.getApp().setNotificationCommand(null);
}
private void handleIntent(Intent intent) {
if (!mActive) {
return;
}
Uri uri = intent.getData();
if (uri != null) {
Fragment fragment;
List<String> pathSegments = uri.getPathSegments();
String command;
String argument;
if (pathSegments.isEmpty()) {
return;
}
if (pathSegments.size() == 1) {
command = uri.getHost();
argument = pathSegments.get(0);
} else {
command = pathSegments.get(1);
argument = pathSegments.size() > 2 ? pathSegments.get(2) : null;
Log.d(TAG,pathSegments.toString());
}
Bundle args = new Bundle();
switch (command) {
case COMMAND_RESET_PASSWORD:
String uid = pathSegments.size() > 2 ? pathSegments.get(2) : null;
String token = pathSegments.size() > 3 ? pathSegments.get(3) : null;
args.putString(Sample.EXTRA_PASSWORD_TOKEN, token);
args.putString(Sample.EXTRA_PASSWORD_UID, uid);
Fragment resetPasswordFragment =
Fragment.instantiate(this, ResetPasswordFragment.class.getName(), args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, resetPasswordFragment)
.addToBackStack(null)
.commit();
break;
case COMMAND_REFERRAL:
if(argument != null)
Sample.getApp().currentUser().setReferralCode(argument);
break;
}
}
}
private void showStoreDetail(String storeId) {
Sample.getApp().setStoreId(null);
Bundle args = new Bundle();
args.putString(Sample.EXTRA_STORE_ID, storeId);
Fragment fragment = Fragment.instantiate(this, StoreDetailFragment.class.getName(), args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment)
.addToBackStack(null)
.commit();
}
private void showMallDetail(String storeId) {
Sample.getApp().setStoreId(null);
Bundle args = new Bundle();
args.putString(Sample.EXTRA_STORE_ID, storeId);
Fragment fragment = Fragment.instantiate(this, MallDetailFragment.class.getName(), args);
getSupportFragmentManager().beginTransaction()
.replace(R.id.content_frame, fragment)
.addToBackStack(null)
.commit();
}
}
when switching between tabs(Bottombar menu's) results in app crash in some devices. But I couldn't reproduce the exception.
This is the stacktrace
Non-fatal Exception: java.lang.RuntimeException: Unable to resume activity {com.beco.ibeco/com.beco.ibeco.app.MainActivity}: java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3000)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3031)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5268)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697)
Caused by java.lang.IllegalStateException: Can not perform this action after onSaveInstanceState
at android.support.v4.app.FragmentManagerImpl.checkStateLoss(FragmentManager.java:1842)
at android.support.v4.app.FragmentManagerImpl.enqueueAction(FragmentManager.java:1860)
at android.support.v4.app.FragmentManagerImpl.popBackStack(FragmentManager.java:781)
at com.beco.ibeco.app.MainActivity$1.onMenuTabSelected(MainActivity.java:74)
at com.beco.ibeco.app.views.bottombar.BottomBar.notifyMenuListener(BottomBar.java:1239)
at com.beco.ibeco.app.views.bottombar.BottomBar.updateSelectedTab(BottomBar.java:1199)
at com.beco.ibeco.app.views.bottombar.BottomBar.selectTabAtPosition(BottomBar.java:437)
at com.beco.ibeco.app.MainActivity.handleCommands(MainActivity.java:347)
at com.beco.ibeco.app.MainActivity.onResume(MainActivity.java:154)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1257)
at android.app.Activity.performResume(Activity.java:6119)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2989)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3031)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1354)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5268)
at java.lang.reflect.Method.invoke(Method.java)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:902)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:697)
Can anyone help me.!
Quick solution is to use .commitAllowingStateLoss(); instead of .commit(); for all FragmentTransactions you are doing for current activity.
There is a bug related to it : https://issuetracker.google.com/issues/36932872
To save the instance and add something to your outState Bundle you can use the following:
#Override
protected void onSaveInstanceState(Bundle outState) {
outState.putString("WORKAROUND_FOR_BUG_KEY","WORKAROUND_FOR_BUG_VALUE");
super.onSaveInstanceState(outState);
}
Also try to add this line if it doesn't work:
transaction.commitAllowingStateLoss();
I have faced this problem
I use .commitAllowingStateLoss(); instead of .commit(); for those FragmentTransactions which fragment state has loss.
In another class you can use .commit();
I've got a fragment with a RecyclerView inside. All is working good but when I press home, navigate in other apps and then go back in my app the view gets recreated and my ArrayList (restored from onSaveInstanceState) is not displayed in my recyclerview that don't work even after updating the List.
Here some code:
-Activity
public class MainActivity extends AppCompatActivity {
FragmentTransaction ft;
BottomNavigationView bottomNavigationView;
int current;
private FirebaseAnalytics mFirebaseAnalytics;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState==null) {
setupFragment();
}
// mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
bottomNavigationView = (BottomNavigationView)
findViewById(R.id.bottom_navigation);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
bottomNavigationView.setOnNavigationItemSelectedListener(
new BottomNavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(#NonNull MenuItem item) {
int id = item.getItemId();
switch (id) {
case R.id.action_golden_hour:
changeFragment(new GoldenFragment(), "GOLDEN");
current=0;
break;
case R.id.action_hyperfocal:
changeFragment(new HyperFragment(), "HYPER");
current=1;
break;
case R.id.action_ir:
changeFragment(new IrFragment(), "IR");
current=2;
break;
case R.id.action_nd:
changeFragment(new NdFragment(), "ND");
current=3;
break;
}
return true;
}
});
}
#SuppressLint("CommitTransaction")
private void setupFragment(){
ft = getSupportFragmentManager().beginTransaction();
ft.add(R.id.main_fragment, new GoldenFragment()).commit();
current=0;
}
#SuppressLint("CommitTransaction")
private void changeFragment(Fragment fragment, String tag){
ft = getSupportFragmentManager().beginTransaction();
ft.replace(R.id.main_fragment, fragment, tag).commit();
}
-Fragment
public class GoldenFragment extends Fragment implements DatePickerDialog.OnDateSetListener{
SupportPlaceAutocompleteFragment autocompleteFragment;
RecyclerView rv;
CustomAdapter adapter;
ProgressBar pb;
ArrayList<Hours> hours;
CardView cv;
TextView emptyGoldenText;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
thisContext = getContext();
setHasOptionsMenu(true);
ampm = !android.text.format.DateFormat.is24HourFormat(thisContext);
hours = new ArrayList<>();
adapter = new CustomAdapter(thisContext, hours);
if(savedInstanceState!=null) {
Log.d(TAG,"inState not null");
hours.clear();
hours = savedInstanceState.getParcelableArrayList("HoursList");
}
Log.d(TAG,"onCreate() called");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
// Inflate the layout for this fragment
if(view == null) {
view = inflater.inflate(R.layout.fragment_golden, container, false);
}
Toolbar goldenToolbar = (Toolbar) view.findViewById(R.id.toolbar_golden);
((AppCompatActivity) getActivity()).setSupportActionBar(goldenToolbar);
emptyGoldenText = (TextView) view.findViewById(R.id.empty_golden_text);
autocompleteFragment = (SupportPlaceAutocompleteFragment) getChildFragmentManager()
.findFragmentById(R.id.place_autocomplete_fragment);
if (autocompleteFragment == null) {
autocompleteFragment = (SupportPlaceAutocompleteFragment) SupportPlaceAutocompleteFragment
.instantiate(thisContext, "com.google.android.gms.location.places.ui.SupportPlaceAutocompleteFragment");
}
autocompleteFragment.setOnPlaceSelectedListener(new PlaceSelectionListener() {
#Override
public void onPlaceSelected(Place place) {
Log.i(TAG, "Place: " + place.getName());
try {
new GeoCoding()
.execute("https://maps.googleapis.com/maps/api/geocode/json?address="+place.getName()+"&key="+geoKEY);
} catch (Exception e) {
Toast.makeText(thisContext,"Cannot contact Google's servers, please try later.", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
#Override
public void onError(Status status) {
Log.i(TAG, "An error occurred: " + status);
}
});
getChildFragmentManager().beginTransaction()
.replace(R.id.place_autocomplete_fragment, autocompleteFragment).commit();
//Initialize RecyclerView
rv = (RecyclerView)view.findViewById(R.id.list_golden);
rv.setLayoutManager(new LinearLayoutManager(thisContext));
DividerItemDecoration dividerItemDecoration = new DividerItemDecoration(rv.getContext(),
getActivity().getResources().getConfiguration().orientation);
rv.addItemDecoration(dividerItemDecoration);
rv.setAdapter(adapter);
cv = (CardView) view.findViewById(R.id.cv_golden);
pb = (ProgressBar) view.findViewById(R.id.progress_bar);
if(savedInstanceState==null) {
Log.d(TAG,"New empty data set");
rv.setVisibility(View.GONE);
cv.setVisibility(View.GONE);
pb.setVisibility(View.INVISIBLE);
}
else{
Log.d(TAG,"Old data set");
adapter.notifyDataSetChanged();
pb.setVisibility(View.INVISIBLE);
rv.setVisibility(View.VISIBLE);
cv.setVisibility(View.VISIBLE);
emptyGoldenText.setVisibility(View.INVISIBLE);
}
Log.d(TAG,"onCreateView() called");
return view;
}
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("HoursList",hours);
Log.d(TAG,"onSaveInstanceState called");
}
SOLVED
Solved by moving
adapter = new CustomAdapter(thisContext, hours);
from onCreate() to onCreateView().
In the activity, you have to save the fragment's instance in onSaveInstanceState() and restore in onCreate().
#Override
public void onCreate(Bundle savedInstanceState) {
...
if (savedInstanceState != null) {
fragment = getSupportFragmentManager().getFragment(savedInstanceState, "KEY");
changeFragment(fragment, "MY TAG")
} else {
setupFragment();
}
...
}
#Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
Fragment fragment = getSupportFragmentManager().findFragmentByTag("MY TAG");
if (fragment != null) {
getSupportFragmentManager().putFragment(outState, "KEY", fragment);
}
}
try this code: in onSaveInstanceState put arraylist
#Override
public void onSaveInstanceState(Bundle outState){
super.onSaveInstanceState(outState);
outState.putParcelableArrayList("HoursList",hours);
Log.d(TAG,"onSaveInstanceState called");
}
In onActivityCreated you check the following conditions:
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
if(savedInstanceState! = null) {
//probably orientation change
Log.d(TAG,"inState not null");
hours.clear();
hours = savedInstanceState.getParcelableArrayList("HoursList");
//check if u get the value print log
}
else {
if (hours != null) {
//returning from backstack, data is fine, do nothing
} else {
//newly created, compute data
hours = computeData();
}
}
}
So my problem is that the buttons that are contained within my fragments throw up an error "Unhandled Exception - Object reference not set to an instance of an object"
I thought because I had referenced the layout that contains the button that this would not cause an error. If anyone could shed some light to what I am doing wrong that would be great. I think I am either missing some vital code or have completely messed it up as I am new to using fragments and understand that they work differently from activities.
This is my MainActivity:
public class MainActivity : ActionBarActivity
{
private SupportToolbar mToolbar;
private MyActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private ListView mLeftDrawer;
private HomeFragment mHomeFragment;
private LogInFragment mLogInFragment;
private MatchCentreFragment mMatchCentreFragment;
private PrevCompFragment mPrevCompFragment;
private PrevFixFragment mPrevFixFragment;
private SettingsFragment mSettingsFragment;
private SocialFragment mSocialFragment;
private UpcomCompFragment mUpcomCompFragment;
private UpcomFixFragment mUpcomFixFragment;
private SupportFragment mCurrentFragment = new SupportFragment();
private Stack<SupportFragment> mStackFragments;
private ArrayAdapter mLeftAdapter;
private List<string> mLeftDataItems;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate(bundle);
SetContentView(Resource.Layout.Main);
mToolbar = FindViewById<SupportToolbar>(Resource.Id.toolbar);
mDrawerLayout = FindViewById<DrawerLayout>(Resource.Id.drawer_layout);
mLeftDrawer = FindViewById<ListView>(Resource.Id.left_drawer);
mHomeFragment = new HomeFragment();
mLogInFragment = new LogInFragment();
mMatchCentreFragment = new MatchCentreFragment();
mPrevCompFragment = new PrevCompFragment();
mPrevFixFragment = new PrevFixFragment();
mSettingsFragment = new SettingsFragment();
mSocialFragment = new SocialFragment();
mUpcomCompFragment = new UpcomCompFragment();
mUpcomFixFragment = new UpcomFixFragment();
mStackFragments = new Stack<SupportFragment>();
mLeftDrawer.Tag = 0;
SetSupportActionBar(mToolbar);
mLeftDataItems = new List<string>();
mLeftDataItems.Add("Home");
mLeftDataItems.Add("Log In");
mLeftDataItems.Add("Match Centre");
mLeftDataItems.Add("Previous Fixtures");
mLeftDataItems.Add("Upcoming Fixtures");
mLeftDataItems.Add("Previous Competitions");
mLeftDataItems.Add("Upcoming Competitions");
mLeftDataItems.Add("Settings");
mLeftDataItems.Add("Social");
mLeftAdapter = new ArrayAdapter<string>(this, Android.Resource.Layout.SimpleListItem1, mLeftDataItems);
mLeftDrawer.Adapter = mLeftAdapter;
mLeftDrawer.ItemClick += MenuListView_ItemClick;
mDrawerToggle = new MyActionBarDrawerToggle(this, mDrawerLayout, Resource.String.openDrawer, Resource.String.closeDrawer);
if (bundle != null)
{
if (bundle.GetString("DrawerState") == "Opened")
{
SupportActionBar.SetTitle(Resource.String.openDrawer);
}
else
{
SupportActionBar.SetTitle(Resource.String.closeDrawer);
}
}
else
{
SupportActionBar.SetTitle(Resource.String.closeDrawer);
}
Android.Support.V4.App.FragmentTransaction trans = SupportFragmentManager.BeginTransaction();
trans.Add(Resource.Id.fragmentContainer, mHomeFragment);
trans.Add(Resource.Id.fragmentContainer, mLogInFragment);
trans.Hide(mLogInFragment);
trans.Add(Resource.Id.fragmentContainer, mMatchCentreFragment);
trans.Hide(mMatchCentreFragment);
trans.Add(Resource.Id.fragmentContainer, mPrevFixFragment);
trans.Hide(mPrevFixFragment);
trans.Add(Resource.Id.fragmentContainer, mUpcomFixFragment);
trans.Hide(mUpcomFixFragment);
trans.Add(Resource.Id.fragmentContainer, mPrevCompFragment);
trans.Hide(mPrevCompFragment);
trans.Add(Resource.Id.fragmentContainer, mUpcomCompFragment);
trans.Hide(mUpcomCompFragment);
trans.Add(Resource.Id.fragmentContainer, mSettingsFragment);
trans.Hide(mSettingsFragment);
trans.Add(Resource.Id.fragmentContainer, mSocialFragment);
trans.Hide(mSocialFragment);
mCurrentFragment = mHomeFragment;
trans.Commit();
}
void MenuListView_ItemClick (object sender, AdapterView.ItemClickEventArgs e)
{
Android.Support.V4.App.Fragment fragment = null;
switch (e.Id)
{
case 0:
ShowFragment(mHomeFragment);
break;
case 1:
ShowFragment(mLogInFragment);
break;
case 2:
ShowFragment(mMatchCentreFragment);
break;
case 3:
ShowFragment(mPrevFixFragment);
break;
case 4:
ShowFragment(mUpcomFixFragment);
break;
case 5:
ShowFragment(mPrevCompFragment);
break;
case 6:
ShowFragment(mUpcomCompFragment);
break;
case 7:
ShowFragment(mSettingsFragment);
break;
case 8:
ShowFragment(mSocialFragment);
break;
}
mDrawerLayout.CloseDrawers();
mDrawerToggle.SyncState();
}
private void ShowFragment (SupportFragment fragment)
{
if (fragment.IsVisible)
{
return;
}
var trans = SupportFragmentManager.BeginTransaction();
fragment.View.BringToFront();
mCurrentFragment.View.BringToFront();
trans.Hide(mCurrentFragment);
trans.Show(fragment);
trans.AddToBackStack(null);
mStackFragments.Push(mCurrentFragment);
trans.Commit();
mCurrentFragment = fragment;
}
public override bool OnOptionsItemSelected(IMenuItem item)
{
switch (item.ItemId)
{
case Android.Resource.Id.Home:
//The hamburger icon was clicked which means the drawer toggle will handle the event
mDrawerToggle.OnOptionsItemSelected(item);
return true;
case Resource.Id.action_refresh:
//Refresh
return true;
case Resource.Id.action_help:
return true;
default:
return base.OnOptionsItemSelected(item);
}
}
public override bool OnCreateOptionsMenu(IMenu menu)
{
MenuInflater.Inflate(Resource.Menu.drawer_menu, menu);
return base.OnCreateOptionsMenu(menu);
}
protected override void OnSaveInstanceState(Bundle outState)
{
if(mDrawerLayout.IsDrawerOpen((int)GravityFlags.Left))
{
outState.PutString("DrawerState", "Opened");
}
else
{
outState.PutString("DrawerState", "Closed");
}
base.OnSaveInstanceState(outState);
}
protected override void OnPostCreate(Bundle savedInstanceState)
{
base.OnPostCreate(savedInstanceState);
mDrawerToggle.SyncState();
}
public override void OnConfigurationChanged(Android.Content.Res.Configuration newConfig)
{
base.OnConfigurationChanged(newConfig);
mDrawerToggle.OnConfigurationChanged(newConfig);
}
}
}
This is one of my fragments (there are several but they all contain basically the same code so far)
public class PrevFixFragment : Android.Support.V4.App.Fragment
{
Button button;
public PrevFixFragment()
{
}
public static Android.Support.V4.App.Fragment newInstance(Context context)
{
PrevFixFragment fragment = new PrevFixFragment();
return fragment;
}
public override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
}
public override View OnCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View view = inflater.Inflate(Resource.Layout.PreviousFixtures, null);
button = View.FindViewById<Button>(Resource.Id.upcombutton);
button.Click += StartNewActivity;
return view;
}
void StartNewActivity(object sender, EventArgs e)
{
Intent intent = new Intent(Activity, typeof(UpcomFixActivity));
StartActivity(intent);
}
}
}
Try moving the following lines to override void OnViewCreated or override void onActivityCreated
button = View.FindViewById<Button>(Resource.Id.upcombutton);
button.Click += StartNewActivity;
You must write View with lowercase view in statement below:
button = View.FindViewById<Button>(Resource.Id.upcombutton);
I have an Activity that contains a number of Fragments that are swapped based on the selected item in a Navigation Drawer. I am trying to retain the current fragment across an orientation change by calling setRetainInstance(true) on the Fragment and then checking if that fragment exists in onCreate(...). However, the Fragment is always null when I try to get it on onCreate(...). I've been banging my head against my desk for hours over this. Can anyone spot a problem?
Relevant parts of activity
public class StartActivity {
private static final String MAIN_FRAGMENT_TAG = "mainFragment";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
...
if(savedInstanceState != null) {
Fragment f = getSupportFragmentManager().findFragmentByTag(MAIN_FRAGMENT_TAG);
if(f == null) {
// FRAGMENT IS ALWAYS NULL
switchToModeForPosition(...);
} else {
setupActionBarForPosition(...);
}
} else {
// Default to events view
switchToModeForPosition(0);
}
}
private void switchToModeForPosition(int position) {
Fragment fragment;
switch (position) {
default:
case 0: //events
fragment = new EventsByWeekFragment();
setupActionBarForEvents();
break;
case 1: //teams
fragment = new AllTeamsListFragment();
setupActionBarForTeams();
break;
case 2: //insights
fragment = new InsightsFragment();
setupActionBarForInsights();
break;
case 3:
startActivity(new Intent(this, SettingsActivity.class));
mDrawerLayout.closeDrawer(mDrawerList);
return;
}
fragment.setRetainInstance(true);
getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment, MAIN_FRAGMENT_TAG).commit();
}
}
use setRetainInstance(true)it in each Fragment class.
public void onCreated(Bundle savedInstanceState)
{
super.onCreated(savedInstanceState);
setRetainInstance(true);
}
Or
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
setRetainInstance(true);
}