How to use back stack properly on activities AND fragments - android

I have 2 activites:
- LoginActivity: it will handle the login stuff later
- MainActivity: the main app, all of the functions will be provided on fragments.
I want to properly use the back stack, but I can't.
What I want (but can't) achieve:
App starts with Login screen. I login (right now press the Start button), after that the main screen appears and the first fragment loads.
Now if I press the back button, the app closes, and that's how it should work, it must not go back to the login screen with a simple back button press.
But now if I click logout (and the Login screen appears), and I press the back button, the app takes me back to the main screen, what is really not ok. If I log out, from the login screen the back button should close the app.
And another problem, regarding also backstack, and fragments:
I have 3 fragments: first, second and third. If I open them after each other (within the main activity of course), and I press the back button, I want it to take me back to the previously opened fragment, or if there's no previous, close the app.
Now it makes it, opens the previous fragment, but at the same time it closes the complete app. (I can see that they are happening right after each other)
What's missing? What should be modified to achieve this (normal) behavior?
Thanks!
My code:
MainActivity:
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
public static final String SP_DATA = "SP_DATA";
public static final String FB_LOGIN_STATUS = "FB_LOGIN_STATUS";
public static final String FLRT = "FLRT";
public SharedPreferences sharedPreferences;
#Override
protected void onCreate(Bundle savedInstanceState) {
sharedPreferences = getSharedPreferences(SP_DATA, MODE_PRIVATE);
boolean bAlreadyLoggedIn = sharedPreferences.getBoolean(FB_LOGIN_STATUS, false);
if (bAlreadyLoggedIn) {
Log.d(FLRT, "Already logged in");
}
else {
Log.d(FLRT, "Not logged in");
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
showFragment(new FirstFragment(),"FirstFragment");
Button btnLogout = (Button) findViewById(R.id.btnLogout);
btnLogout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
logout();
showActivity(MainActivity.this, LoginActivity.class);
}
});
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
private void showActivity(Context context_fromActivity, Class<?> class_toActivty){
Intent intent = new Intent(context_fromActivity, class_toActivty);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
private void logout() {
Log.d(FLRT, "Logging out...");
sharedPreferences = getSharedPreferences(SP_DATA, MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(FB_LOGIN_STATUS, false);
editor.commit();
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
if (getFragmentManager().getBackStackEntryCount() > 0 ){
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_first_layout) {
showFragment(new FirstFragment(), "FirstFragment");
}
else if (id == R.id.nav_second_layout) {
showFragment(new SecondFragment(), "SecondFragment");
}
else if (id == R.id.nav_third_layout) {
showFragment(new ThirdFragment(), "ThirdFragment");
}
else if (id == R.id.nav_share) {
}
else if (id == R.id.nav_send) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
private void showFragment(Fragment fragment, String sFragmentTAG) {
FragmentManager fragmentManager = getFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (fragmentManager.findFragmentByTag(sFragmentTAG) != null) {
Log.d(FLRT, "Fragment found, using existing one: " + sFragmentTAG);
fragment = fragmentManager.findFragmentByTag(sFragmentTAG);
}
fragmentTransaction.replace(R.id.fragmentContainer, fragment, sFragmentTAG);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
}
LoginActivity:
public class LoginActivity extends AppCompatActivity {
public static final String SP_DATA = "SP_DATA";
public static final String FB_LOGIN_STATUS = "FB_LOGIN_STATUS";
public static final String FLRT = "FLRT";
public SharedPreferences sharedPreferences;
private Button btn_start;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
btn_start = (Button) findViewById(R.id.btn_start);
btn_start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
login();
showActivity(LoginActivity.this, MainActivity.class);;
}
});
}
private void showActivity(Context context_fromActivity, Class<?> class_toActivty){
Intent intent = new Intent(context_fromActivity, class_toActivty);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
private void login() {
Log.d(FLRT, "Logging in...");
sharedPreferences = getSharedPreferences(SP_DATA, MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(FB_LOGIN_STATUS, true);
editor.commit();
}
}

About switching between Activities.
One important thing.
In showActivity() use finish() to kill current Activity when going to another. If it doesn't help - see below.
Try to use also FLAG_ACTIVITY_NEW_TASK with your current flag, because FLAG_ACTIVITY_CLEAR_TOP will close only Activities in task above current Activity, but not below.
So, it would be this: intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);
Another option is to use: FLAG_ACTIVITY_CLEAR_TASK only - new Activity will clear the task and become root in it.
If both won't help - use android:launchMode = "singleInstance" in Manifest for each Actitivy.
About Fragments - I see a little mistake in your code: it calls super.onBackPressed(); before popping Fragment from BackStack
I would change like this:
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (getFragmentManager().getBackStackEntryCount() > 0 ){
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
!! Also you should test this line: getFragmentManager().getBackStackEntryCount() > 0 with 0 and 1 in condition (because in current implementation in my project FragmentContainer is considering as first, zero value in a BackStack). Just test 0 and 1 to see which works.
Thanks.
PS. Few more tips.
You can declare FragmentManager fragmentManager in your Activity in order to create it one time only in onCreate(). It would be better than get it each time.
Consider change this:
if (id == R.id.nav_first_layout) {
showFragment(new FirstFragment(), "FirstFragment");
}
else if (id == R.id.nav_second_layout) {
showFragment(new SecondFragment(), "SecondFragment");
}
else if (id == R.id.nav_third_layout) {
showFragment(new ThirdFragment(), "ThirdFragment");
}
else if (id == R.id.nav_share) {
}
else if (id == R.id.nav_send) {
}
To:
switch (item.getItemId()) {
case R.id.nav_first_layout:
showFragment(new FirstFragment(), "FirstFragment");
break;
case ...
}
and so on. The code would be more pretty :)

Related

In fragment I want to click back how to show alert dialog

I am using navigation menu in an Activity. When I click menu, it goes to particular fragment that time I give addtobackstack(null). I want to fix these 2 issues:
I want to show do you want to exit app through a popup In the back fragment
Assume that I traverse from Fragment A to B and then B to C. If I give back in the Fragment C I want to come the main page, without showing the Fragment B.
This is my Home Activity:
package school.wyse.app.activities;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
public class ParentHomeActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
ServerUtils servutil;
GridLayoutManager grid;
Toolbar toolbar;
private View navHeader;
LinearLayout profile;
ImageView msglist;
ArrayList<StudentProfile> lang_list_new;
public RecyclerView studentsListRecyclerView;
public ParentMenuDashoard mStudAdapter;
StudentProfile[] profiles;
private StudentProfile[] studentCachedData;
Context ctx;
DrawerLayout drawer;
ImageView imageViewstaff;
String tenent_id,profilename,image,userphone;
Integer id,roleid;
String backStateName;
TextView profile_phone,profile_name;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
setContentView(R.layout.activity_parent_home);
backStateName = this.getClass().getName();
ctx=this;
Toast.makeText(ctx, "backStateName--"+backStateName, Toast.LENGTH_SHORT).show();
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
navHeader=navigationView.getHeaderView(0);
studentsListRecyclerView = (RecyclerView) navHeader.findViewById(R.id.messageWindowRecycler);
ParentDashboard parentDashboard = new ParentDashboard();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.content_frame, parentDashboard, parentDashboard.getTag()).commit();
toolbar.setTitle("Dashboard");
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void onBackPressed() {
try {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.home, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
/* if (id == R.id.action_msg) {
return true;
}*/
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
// Handle navigation view item clicks here.
int id = item.getItemId();
if (id == R.id.nav_dashboard) {
ParentDashboard parentDashboard = new ParentDashboard();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.content_frame, parentDashboard, parentDashboard.getTag()).addToBackStack(null).commit();
//toolbar.setTitle("Dashboard");
} else if (id == R.id.nav_teachers) {
TeacherList teacherList = new TeacherList();
FragmentManager manager = getSupportFragmentManager();
// manager.beginTransaction().replace(R.id.id_content_frame, accountsMenuListFragment, "AccountsMenu").addToBackStack(" ").commit();
manager.beginTransaction().replace(R.id.content_frame, teacherList, teacherList.getTag()).addToBackStack(null).commit();
// toolbar.setTitle("Teachers");
} else if (id == R.id.nav_attendance) {
AttendanceFragment attendanceFragment = new AttendanceFragment();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.content_frame, attendanceFragment, attendanceFragment.getTag()).addToBackStack(null).commit();
// toolbar.setTitle("Attendance");
} else if (id == R.id.nav_consumablity) {
ParentConsumablityFragment parentConsumablityFragment = new ParentConsumablityFragment();
FragmentManager manager = getSupportFragmentManager();
manager.beginTransaction().replace(R.id.content_frame, parentConsumablityFragment, parentConsumablityFragment.getTag()).addToBackStack(null).commit();
// toolbar.setTitle("Attendance");
}
else {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
}
Okay, sorry for late reply
This part goes in onBackPressed() of your activity, which basically check if you have fragments attached (so it won't perform the native back, which closes the app)
if (childFragments.size() > 0) {
if (childFragments.get((childFragments.size() - 1)) != null) {
childFragments.remove(childFragments.size() - 1);
return;
}
}
All you have to do is add/remove items to this array every time you attach / detach fragments :)
For your particular case when you are on fragment C and want to go back to fragment A without showing fragment B, I suggest you make a public function that remove all fragments from ArrayList except last one (from position 0)
Use below code in mainactivity where you want to show appexit:
#Override
public void onBackPressed() {
if (doubleBackToExitPressedOnce) {
super.onBackPressed();
finish();
return;
}
this.doubleBackToExitPressedOnce = true;
Toast.makeText(this, "Please click BACK again to exit", Toast.LENGTH_SHORT).show();
new Handler().postDelayed(new Runnable() {
#Override
public void run() {
doubleBackToExitPressedOnce = false;
}
}, 2000);
}
When moving fragment A to B do not add "addbackstack". When moving fragment B to C add "addbackstack("C")"
first of all, you have to take care of your second issue as it will lead to easy handle for the first issue, hence you have to take care of how to initiate the fragments in order to always coming to the first fragment while hitting back regardless the flow of fragments that lead to the current fragment, to do so, just initiate the fragments like the following:
/**
* To initiate any fragment
*/
private void showAnyFragment(Fragment fragmentToShow) {
getSupportFragmentManager().popBackStack();
FrameLayout frameLayout = (FrameLayout) findViewById(R.id.content);
frameLayout.setVisibility(View.VISIBLE);
getSupportFragmentManager().beginTransaction()
.replace(R.id.content, fragmentToShow)
.addToBackStack(null)
.commit();
}
/**
* When (for a reason) you want to initiate the main fragment (FragmentA)
*/
private void homeClicked() {
getSupportFragmentManager().popBackStack();
}
Now, fragmentA is your main fragment, when going from A to B to C to D and click back button it will go back to A directly.
Coming to your second issue, it will be straight forward as you already keeping only fragmentA always in the back stack, so onBackPressed() function of the Activity will not be called unless there are No other fragment other than FragmentAis being displayed(e.g if you are in fragmentC and you click back button, the onBackPressed() function will not be called), so you are sure that when you come inside onBackPressed() function of the activity that the currently running fragment is FragmentA which is your main page fragment.
so if you want to display a popup while the user trying to exit the app (he would be in FragmentA and hiitting Back), all you have to do is to override the onBackPressed() method of the MainActivity that holds the fragments:
#Override
public void onBackPressed() {
// the user here is in FragmentA(main page),
and he is clicking back to exit the app.
// TODO show popup here or do whatever you want
}

How to implement onBackPress from fragment in navigation drawer to MainActivity

I want to implement onBackPress to my fragment but i don't know how. When i go to another fragment (in this case, my fragment is the one from my ActivityHome and i'm using standard NavigationDrawer from android stuudio).
Here is my code for ActivityHome
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_home);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
FragmentHome fragment = new FragmentHome();
fragmentTransaction.add(R.id.containerID, fragment);
fragmentTransaction.commit();
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.activity_home, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_logout) {
Toast.makeText(getApplicationContext(),
"Akun anda telah dikeluarkan!", Toast.LENGTH_LONG).show();
Intent logout = new Intent(ActivityHome.this, ActivityMain.class);
startActivity(logout);
return true;
}
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == R.id.nav_home){
ActivityHome.this.getSupportFragmentManager().beginTransaction().replace(R.id.containerID, FragmentHome.newInstance()).commit();
}else if (id == R.id.nav_profile){
ActivityHome.this.getSupportFragmentManager().beginTransaction().replace(R.id.containerID, Profile.newInstance()).commit();
}
else if (id == R.id.nav_history){
ActivityHome.this.getSupportFragmentManager().beginTransaction().replace(R.id.containerID, History.newInstance()).commit();
}
else if (id == R.id.nav_about_us){
ActivityHome.this.getSupportFragmentManager().beginTransaction().replace(R.id.containerID, AboutUs.newInstance()).commit();
}
else if (id == R.id.nav_ganti_kata_sandi){
ActivityHome.this.getSupportFragmentManager().beginTransaction().replace(R.id.containerID, GantiKataSandi.newInstance()).commit();
}
else if (id == R.id.nav_share){
ActivityHome.this.getSupportFragmentManager().beginTransaction().replace(R.id.containerID, Share.newInstance()).commit();
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
I hope u guys can help me with my problem.
I have webview in fragment, I used this code to detect backpress code in mainactivity OnbackPressed():
Fragment webview = getSupportFragmentManager().findFragmentByTag("BLOG");
if (webview instanceof BlogFragment) {
boolean goback = ((BlogFragment) webview).canGoBack();
if (!goback) {
} else {
((BlogFragment) webview).goBack();
}
}
Make sure you start fragment like:
getSupportFragmentManager()
.beginTransaction()
.addToBackStack(null)
.replace(R.id.frame_content, new BlogFragment(), "BLOG")
.commit();
To open fragment from activity.
Fragment fragment = Fragment.newInstance();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.setCustomAnimations(R.anim.fragment_slide_left_enter,
R.anim.fragment_slide_left_exit, R.anim.fragment_slide_right_enter,
R.anim.fragment_slide_right_exit);
addFragmentToActivity(fragmentTransaction, Fragment, R.id
.content_frame);
public void addFragmentToActivity(#NonNull FragmentTransaction transaction,
#NonNull Fragment fragment, int frameId) {
transaction.addToBackStack(fragment.getClass().getName());
transaction.add(frameId, fragment, fragment.getClass().getName());
transaction.commit();
}
That's how I add fragment from HomeActivity and For back Call override method OnBackPressed in HomeActivity.
#Override
public void onBackPressed() {
if (getSupportFragmentManager().getBackStackEntryCount() > 1) {
getSupportFragmentManager().popBackStackImmediate();
}
You can get event when back button pressed from any fragment in Activity's onBackPressed() method.
Suppose you've pressed back from HomeFragment then you can get onBackPressed in Activity like following :
#Override
public void onBackPressed() {
HomeFragment fragment = (Fragment)findFragmentById(// fragment id);
if(fragment!=null && fragment.isVisible()){
// Here you can code for Home Fragment's onBackPress()
}
super.onBackPressed();
}

How to show a text from one fragment in another fragment?

I WAS WORKING BY THE EXAMPLE YOU JUST GAVE ME AS DUPLICATE, READ THE ENTIRE POST, TY
I'm making a simple app with sliding menu by using the template provided by android studio. And I have to use fragments to switch between items of the sliding menu.
What I wanna do? (check app design at the bottom)
When I click on button pass data it should set the text in the Fragment B to the text that I entered in a Fragment A but without going directly to the Fragment B. So when I press the button pass data then I wanna go to the sliding menu and select item that containts fragment B and then I wanna see the text from Fragment A. Thanks in advance.
public class MainActivity extends AppCompatActivity implements FragmentA.DataPassListener {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.nav_camera) {
// Handle the camera action
displayFragmentA();
} else if (id == R.id.nav_gallery) {
displayFragmentB();
} else if (id == R.id.nav_slideshow) {
} else if (id == R.id.nav_manage) {
} else if (id == R.id.nav_share) {
} else if (id == R.id.nav_send) {
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
});
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#Override
public void passData(String data) {
FragmentB fragmentB = new FragmentB();
Bundle args = new Bundle();
args.putString("data", data);
fragmentB.setArguments(args);
//getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragmentB).commit();
//it works with the commented part but I dont wanna go directly to the fragment when I press pass data button
}
public void displayFragmentA() {
FragmentA frag = new FragmentA();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, frag);
fragmentTransaction.commit();
}
public void displayFragmentB() {
FragmentB frag = new FragmentB();
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.fragment_container, frag);
fragmentTransaction.commit();
}
}
Fragment A code:
public class FragmentA extends Fragment {
DataPassListener mCallback;
public interface DataPassListener {
public void passData(String data);
}
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// Make sure that container activity implement the callback interface
try {
mCallback = (DataPassListener) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement DataPassListener");
}
}
public FragmentA() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_a, container, false);
final EditText input = (EditText) view.findViewById(R.id.etInputID);
Button passDataButton = (Button) view.findViewById(R.id.bPassDataID);
passDataButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mCallback.passData(input.getText().toString());
}
});
return view;
}
}
Fragment B code:
public class FragmentB extends Fragment {
TextView showReceivedData;
public FragmentB() {
// Required empty public constructor
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_fragment_b, container, false);
showReceivedData = (TextView) view.findViewById(R.id.showReceivedData);
Bundle args = getArguments();
if (args != null) {
showReceivedData.setText(args.getString("data"));
} else {
Toast.makeText(getActivity(), "didnt get the bundle from mainactivity", Toast.LENGTH_LONG).show();
}
return view;
}
}
Design of the app:
If these two fragments use same activity,
to set value to fragment :
getActivity().getIntent().putExtra("key", "value");
To get value from fragment :
getActivity().getIntent().getExtras().getString("key");

Something went wrong with the Activity lifecycle, not normal behavior by pressing home or task switch button

Something is not OK in my code. Normally the activity lifecycle is
- at starting app: onCreate --> onStart --> onResume
- at closing app: onPause --> onStop --> onDestroy
- pressing the home button or the task switch button: onPause --> onStop
- coming back to the already opened app from another app: onStart --> onResume
But for some reason my app also calls onDestroy when I press the home button or the task switch button, and it calls onCreate, when I go back to the already opened app.
My app has 2 Activites:
- LoginActivity, which should appear first, if nobody is logged on, or if the logout button is pressed
- MainActivity to handle the main functions.
Please help me identify what causes this not normal behavior of lifecycle.
Thanks!
MainActivity:
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener {
public Helper helper = new Helper(this);
public static final String SP_DATA = "SP_DATA";
public static final String FB_LOGIN_STATUS = "FB_LOGIN_STATUS";
public static final String FLRT = "FLRT";
public SharedPreferences sharedPreferences;
public FragmentManager fragmentManager = getFragmentManager();
#Override
protected void onCreate(Bundle savedInstanceState) {
Log.d(FLRT, "onCreate");
helper.makeToast("onCreate");
sharedPreferences = getSharedPreferences(SP_DATA, MODE_PRIVATE);
boolean bAlreadyLoggedIn = sharedPreferences.getBoolean(FB_LOGIN_STATUS, false);
if (bAlreadyLoggedIn) {
Log.d(FLRT, "Already logged in");
}
else {
Log.d(FLRT, "Not logged in");
Intent intent = new Intent(MainActivity.this, LoginActivity.class);
startActivity(intent);
}
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
showFragment(new FirstFragment(),"FirstFragment");
Button btnLogout = (Button) findViewById(R.id.btnLogout);
btnLogout.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
logout();
showActivity(MainActivity.this, LoginActivity.class);
}
});
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
drawer.setDrawerListener(toggle);
toggle.syncState();
NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
navigationView.setNavigationItemSelectedListener(this);
}
private void showActivity(Context context_fromActivity, Class<?> class_toActivty){
Intent intent = new Intent(context_fromActivity, class_toActivty);
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
MainActivity.this.finish();
}
private void logout() {
Log.d(FLRT, "Logging out...");
sharedPreferences = getSharedPreferences(SP_DATA, MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(FB_LOGIN_STATUS, false);
editor.commit();
}
#Override
public void onBackPressed() {
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
} else if (getFragmentManager().getBackStackEntryCount() > 1 ){
getFragmentManager().popBackStack();
} else {
super.onBackPressed();
}
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
#SuppressWarnings("StatementWithEmptyBody")
#Override
public boolean onNavigationItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.nav_first_layout:
showFragment(new FirstFragment(), "FirstFragment");
break;
case R.id.nav_second_layout:
showFragment(new SecondFragment(), "SecondFragment");
break;
case R.id.nav_third_layout:
showFragment(new ThirdFragment(), "ThirdFragment");
break;
case R.id.nav_share:
break;
case R.id.nav_send:
break;
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
drawer.closeDrawer(GravityCompat.START);
return true;
}
private void showFragment(Fragment fragment, String sFragmentTAG) {
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
if (fragmentManager.findFragmentByTag(sFragmentTAG) != null) {
Log.d(FLRT, "Fragment found, using existing one: " + sFragmentTAG);
fragment = fragmentManager.findFragmentByTag(sFragmentTAG);
}
fragmentTransaction.replace(R.id.fragmentContainer, fragment, sFragmentTAG);
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
#Override
protected void onStart() {
super.onStart();
Log.d(FLRT, "onStart");
helper.makeToast("onStart");
}
#Override
protected void onResume() {
super.onResume();
Log.d(FLRT, "onResume");
helper.makeToast("onResume");
}
#Override
protected void onPause() {
super.onPause();
Log.d(FLRT, "onPause");
helper.makeToast("onPause");
}
#Override
protected void onStop() {
super.onStop();
Log.d(FLRT, "onStop");
helper.makeToast("onStop");
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d(FLRT, "onDestroy");
helper.makeToast("onDestroy");
}
}
LoginActivity:
public class LoginActivity extends AppCompatActivity {
public static final String SP_DATA = "SP_DATA";
public static final String FB_LOGIN_STATUS = "FB_LOGIN_STATUS";
public static final String FLRT = "FLRT";
public SharedPreferences sharedPreferences;
private Button btn_start;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_login);
btn_start = (Button) findViewById(R.id.btn_start);
btn_start.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
login();
showActivity(LoginActivity.this, MainActivity.class);;
}
});
}
private void showActivity(Context context_fromActivity, Class<?> class_toActivty){
Intent intent = new Intent(context_fromActivity, class_toActivty);
//intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
LoginActivity.this.finish();
}
private void login() {
Log.d(FLRT, "Logging in...");
sharedPreferences = getSharedPreferences(SP_DATA, MODE_PRIVATE);
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putBoolean(FB_LOGIN_STATUS, true);
editor.commit();
}
}
Nothing surprising here,
The behavior of onDestroy() method is
In some situations System simply kill the activity's hosting process without calling this method. OR System can directly destroy your app If its getting into low memory situations even your app is in onStop() event, And another thing to notice is onStop() method also may not be called, in low memory situations.
See onDestroy() method in details.
Ok, when you call MainActivity.this.finish(); or LoginActivity.this.finish(); the activity is distroyed. try not call finish() if you don't want destroy needed activity
I found the problem: in the mainfest file android:noHistory="true"
was set for both activities. Now the activity lifecycle is working fine.
However now from the Login screen I can simply can go back to the Main screen with pressing the Back button... and that's not ok. :)

Google Navigation Drawer, handling backpress to set correct checked ite

Currently Used Google Navigation Drawer, having some problem when user backpress.
When user backpress, they didn't update menu Item
Example When I click the App. The sequence are A>B>C>B>C ,if I backpress I wanted to be C>B>A. How should I code this way out ?
My code
public class MainActivity extends AppCompatActivity {
private String appTitle;
private Toolbar toolbar;
private NavigationView navigationView;
private DrawerLayout drawerLayout;
private TextView toolbarTitle;
private Fragment fragment;
private FragmentManager fragmentManager;
private Title title;
private MenuItem menuItem2;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Actionbar
toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
toolbarTitle = (TextView) toolbar.findViewById(R.id.toolbar_title);
toolbarTitle.setTextColor(Color.parseColor("#FFFFFF"));
setTitle("");
fragmentManager = getSupportFragmentManager();
fragment= new HomeFragment();
title = new Title(getApplicationContext());
fragmentManager.beginTransaction().replace(R.id.content_frame,fragment , title.getStrHome()).commit();
navigationView = (NavigationView) findViewById(R.id.navigation_view);
navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {
#Override
public boolean onNavigationItemSelected(MenuItem menuItem) {
menuItem2 = menuItem;
menuItem.setChecked(true);
drawerLayout.closeDrawers();
if (menuItem.getItemId() == R.id.nav_home) {
fragment = new HomeFragment();
appTitle = title.getStrHome();
} else if ((menuItem.getItemId() == R.id.nav_direction)) {
fragment = new DirectionFragment();
appTitle = title.getStrDirection();
} else if ((menuItem.getItemId() == R.id.nav_more)) {
fragment = new MoreFragment();
appTitle = title.getStrMore();
} else if((menuItem.getItemId()==R.id.nav_directory)){
fragment = new DirectoryFragment();
appTitle = title.getStrDirectory();
}
else {
Toast.makeText(getApplicationContext(), "Error", Toast.LENGTH_SHORT).show();
}
replaceFragment(fragment,appTitle);
return true;
}
});
drawerLayout = (DrawerLayout) findViewById(R.id.drawer);
ActionBarDrawerToggle actionBarDrawerToggle =
new ActionBarDrawerToggle
(this,drawerLayout,toolbar,R.string.drawer_open,R.string.drawer_close){
#Override
public void onDrawerClosed(View drawerView) {
super.onDrawerClosed(drawerView);
}
#Override
public void onDrawerOpened(View drawerView) {
super.onDrawerOpened(drawerView);
}
};
drawerLayout.setDrawerListener(actionBarDrawerToggle);
actionBarDrawerToggle.syncState();
}
public void onBackPressed() {
if(drawerLayout.isDrawerOpen(GravityCompat.START)){
drawerLayout.closeDrawer(GravityCompat.START);
}
else {
if (fragmentManager.getBackStackEntryCount() > 0 ){
fragmentManager.popBackStack();
toolbarTitle.setText(appTitle);
menuItem2.setChecked(true);
} else {
finish();
}
}
}
public void replaceFragment(Fragment fragment, String tag){
toolbarTitle.setText(tag);
FragmentTransaction ft = fragmentManager.beginTransaction().replace(R.id.content_frame, fragment, tag);
ft.addToBackStack(tag);
ft.commit();
}
#Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
#Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
As stated on the official page on Android tasks and back stack you can see how you can accomplish your desired behaviour using the FLAG_ACTIVITY_CLEAR_TOP in your Intent flags. This picture demonstrates it very well.
Your regular back button proceeds as:
When you specify this flag, you get a behavior like you need
Edit:
The official documentation states:
FLAG_ACTIVITY_CLEAR_TOP
If the activity being started is already running in the current task, then instead of launching a new instance of that activity, all of the
other activities on top of it are destroyed
This means, there will be no duplicates of your different Activities, and you will have a clean Back Stack.
In your example A>B>C>B>C would not be possible. Instead it would be A>B>C, since B and C already exist in the stack, they will not be added, but replaced instead.
Study the Android Activity Launch Mode.
here is the clear Explanation available.
Just take a look.

Categories

Resources