I have my main activity which contains 2 fragments:
MainActivity
public class MainActivity extends AppCompatActivity implements FragmentOne.OnFragmentOneInteractionListener, FragmentTwo.OnFragmentTwoInteractionListener{
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
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;
}
// Create a new Fragment to be placed in the activity layout
FragmentOne fragmentOne = new FragmentOne ();
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, fragmentOne ).commit();
}
}
This activity initially display fragment one.
Fragment one has a button which listens and when clicked it will replace itself with fragment two. When the button is clicked the interface in fragment one gets
//Main acitivty has this method which is a a method the interface in fragment one requires
#Override
public void goToFragmentTwo() {
//Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
// setSupportActionBar(toolbar);
// Create fragment and give it an argument specifying the article it should show
FragmentTwo fragmentTwo = new FragmentTwo ();
FragmentTransaction transaction = getSupportFragmentManager().beginTransaction();
// Replace whatever is in the fragment_container view with this fragment,
// and add the transaction to the back stack so the user can navigate back
transaction.replace(R.id.fragment_container, fragmentTwo );
transaction.addToBackStack(FragmentTwo.BACKSTACK_TAG);
// Commit the transaction
transaction.commit();
}
If the android back button or the back button in the toolbar gets called the fragments need to have a confirm dialog which asks are you sure you want to leave. If Ok then I have a second activity called the HomeActivity (this activity is the parent activity of MainActivity) which it needs to go to, or if cancel it needs to just close the dialog and stay in the current fragment.
So in the MainActivity I have overrode the onBackPressed method which displays a :
#Override
public void onBackPressed() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Do you want to leave? ");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
MainActivity.super.onBackPressed();
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
}
});
builder.show();
}
I am experiencing two problems with this code:
1) Pressing the back button in the toolbar doesn't display a dialog
2) The dialog's OK and Cancel features are not working correctly.
Essentially what I am trying to accomplish is I have a HomeActivity which has a button to navigate to the MainActivity. When the MainActivity gets called I will start a workflow where each fragment is a section of that workflow. If the back button is pressed this workflow needs to be discarded and the user should be returned back to the HomeActivty.
i am assuming you are using ActionBar.
Try adding this in your activity:
#Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case android.R.id.home:
onBackPressed();
return true;
}
return false;
}
#Override
public void onBackPressed() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Do you want to leave? ");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
MainActivity.super.onBackPressed();
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
}
});
builder.show();
}
1) You should make your toolbar back button call onBackPressed() from your activity, so they both share the same functionality.
See onSupportNavegationUp() in the main activity.
2) Have your Main Activity control what happens with the fragment, but let the fragments handle any back press if they must.
I hope this is of use to you.
Manifest
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.johnurrutia.so_43172788">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/Theme.AppCompat.Light.NoActionBar">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.johnurrutia.so_43172788.MainActivity">
<android.support.v7.widget.Toolbar
android:id="#+id/toolBar"
android:layout_width="0dp"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
android:elevation="4dp"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar"
app:popupTheme="#style/ThemeOverlay.AppCompat.Light"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent">
</android.support.v7.widget.Toolbar>
<FrameLayout
android:id="#+id/fragment_container"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toBottomOf="#id/toolBar"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:layout_editor_absoluteY="8dp">
</FrameLayout>
</android.support.constraint.ConstraintLayout>
fragment_one.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/btnGoFrag2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Go To Fragment TWO" />
</LinearLayout>
fragment_two.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/goToFragmentOne"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Go To Fragment One" />
</LinearLayout>
MainActivity.java
public class MainActivity extends AppCompatActivity
implements FragmentOne.OnFragmentOneInteractionListener, FragmentTwo.OnFragmentTwoInteractionListener {
public static final int FRAGMENT_ONE = 0;
public static final int FRAGMENT_TWO = 1;
private Toolbar toolbar;
private FragmentOne fragmentOne;
private FragmentTwo fragmentTwo;
private ArrayList<Fragment> fragments = new ArrayList<>();
private int currentFragment = 0;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
toolbar = (Toolbar) findViewById(R.id.toolBar);
setSupportActionBar(toolbar);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
// Check that the activity is using the layout version with
// the fragment_container FrameLayout
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;
}
// Create a new Fragment to be placed in the activity layout
fragmentOne = new FragmentOne();
fragmentTwo = new FragmentTwo();
fragments.add(FRAGMENT_ONE, fragmentOne);
fragments.add(FRAGMENT_TWO, fragmentTwo);
// Add the fragment to the 'fragment_container' FrameLayout
getSupportFragmentManager().beginTransaction()
.add(R.id.fragment_container, fragmentOne,"FRAGMENT_ONE")
.add(R.id.fragment_container, fragmentTwo, "FRAGMENT_TWO")
.hide(fragmentTwo)
.show(fragmentOne)
.commit();
}
}
#Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
#Override
public void onBackPressed() {
boolean fragmentProcessedTheEvent = ( (BackButtonListener) fragments.get(currentFragment)).onBackPressed();
if(!fragmentProcessedTheEvent) {
//The event is for Main Activity to exit
showActivityExitDialog();
}
}
public void showActivityExitDialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Do you want to leave? ");
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
finish();
}
});
builder.setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
dialog.dismiss();
}
});
builder.show();
}
private void switchToFragment(int pos) {
if (currentFragment != pos) {
getSupportFragmentManager().beginTransaction()
.hide(fragments.get(currentFragment))
.show(fragments.get(pos))
.commit();
currentFragment = pos;
}
}
public void goToFragmentTwo(){
switchToFragment(FRAGMENT_TWO);
}
public void goToFragmentOne(){
switchToFragment(FRAGMENT_ONE);
}
}
FragmentOne.java
public class FragmentOne extends Fragment implements BackButtonListener{
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_one, container, false);
Button goToFragmentTwoBtn = (Button) v.findViewById(R.id.btnGoFrag2);
goToFragmentTwoBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
( (OnFragmentOneInteractionListener) getActivity() ).goToFragmentTwo();
}
});
return v;
}
public interface OnFragmentOneInteractionListener{
public void goToFragmentTwo();
}
#Override
public boolean onBackPressed() {
/*
* if(fragment_has_any_use_for_back_press){
* process_it_here();
* return EVENT_PROCESSED;
* }
*
* */
return EVENT_IGNORED;
}
}
FragmentTwo.java
public class FragmentTwo extends Fragment implements BackButtonListener{
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_two, container, false);
Button goToFragmentTwoBtn = (Button) v.findViewById(R.id.goToFragmentOne);
goToFragmentTwoBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
( (FragmentTwo.OnFragmentTwoInteractionListener) getActivity() ).goToFragmentOne();
}
});
return v;
}
#Override
public boolean onBackPressed() {
/*
* if(fragment_has_any_use_for_back_press){
* process_it_here();
* return EVENT_PROCESSED;
* }
*
* */
return EVENT_IGNORED;
}
public interface OnFragmentTwoInteractionListener{
public void goToFragmentOne();
}
}
BackButtonListener.java
public interface BackButtonListener {
public static final boolean EVENT_PROCESSED = true;
public static final boolean EVENT_IGNORED = false;
public boolean onBackPressed();
}
Related
I have 4 activities, when i press home button, it goes in background and when i open it from background, it starts from the activity from where i resume, but i want to open Launcher activity always because in my first activity password is set and i want the user to type password every time when the app is open
android:clearTaskOnLaunch="true"
android:finishOnTaskLaunch="true"
android:launchMode="singleInstance"
`
I have tried this code in Manifest,but it is also not working.
I have also tried this but unfortunately result is same
#Override
protected void onStop() {
sliderShow.stopAutoCycle();
super.onStop();
GalleryBrowserActivity.this.finish();
Log.d("value","value on Stop"+("position"));
}
UPDATE
Hi, I tried to solve this issue so that it can be useful for future too. May be my attempt will not suit in each and every application requirement but it can be helpful in many situations. This is a demo I tried using fragments and I assume this is the only possible way to achieve this requirement. Correct me if I am wrong anywhere. Here is the code:
MainActivity.java
public class MainActivity extends AppCompatActivity {
private Fragment mCurrentFragment;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
addFragment(MainFragment.newInstance());
}
public void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getSupportFragmentManager();
String backStackTag = fragment.getClass().getName();
boolean fragmentPoped = fragmentManager.popBackStackImmediate(backStackTag, 0);
if (!fragmentPoped) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame, fragment, backStackTag);
if (backStackTag != null) {
fragmentTransaction.addToBackStack(backStackTag);
}
fragmentTransaction.commitAllowingStateLoss();
}
}
public void addFragment(Fragment fragment) {
FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
if (mCurrentFragment != null) {
Fragment f = getSupportFragmentManager().findFragmentByTag(mCurrentFragment.getClass().getName());
if (f != null) {
fragmentTransaction.remove(f);
}
}
fragmentTransaction.add(R.id.frame, fragment, fragment.getClass().getName());
fragmentTransaction.commit();
mCurrentFragment = fragment;
}
public void replaceInMainFragment(Fragment fragment) {
if (mCurrentFragment != null && mCurrentFragment instanceof MainFragment) {
((MainFragment) mCurrentFragment).replaceFragment(fragment);
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/frame"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</RelativeLayout>
MainFragment.java
public class MainFragment extends Fragment {
private View mView;
private Fragment mCurrentFragment;
public static MainFragment newInstance() {
MainFragment loginFragment = new MainFragment();
return loginFragment;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_main, container, false);
Log.e("MainFragment", "onCreateView");
return mView;
}
#Override
public void onStart() {
super.onStart();
Log.e("MainFragment", "onStart");
addFragment(LoginFragment.newInstance());
}
public void replaceFragment(Fragment fragment) {
FragmentManager fragmentManager = getActivity().getSupportFragmentManager();
String backStackTag = fragment.getClass().getName();
boolean fragmentPoped = fragmentManager.popBackStackImmediate(backStackTag, 0);
if (!fragmentPoped) {
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
fragmentTransaction.replace(R.id.frame_main, fragment, backStackTag);
if (backStackTag != null) {
fragmentTransaction.addToBackStack(backStackTag);
}
fragmentTransaction.commitAllowingStateLoss();
}
}
public void addFragment(Fragment fragment) {
removeAllFragmentFromBackstack();
FragmentTransaction fragmentTransaction = getActivity().getSupportFragmentManager().beginTransaction();
if (mCurrentFragment != null) {
Fragment f = getActivity().getSupportFragmentManager().findFragmentByTag(mCurrentFragment.getClass().getName());
if (f != null) {
fragmentTransaction.remove(f);
}
}
fragmentTransaction.add(R.id.frame_main, fragment, fragment.getClass().getName());
fragmentTransaction.commit();
mCurrentFragment = fragment;
}
private void removeAllFragmentFromBackstack() {
FragmentManager fm = getActivity().getSupportFragmentManager();
for (int i = 0; i < fm.getBackStackEntryCount(); ++i) {
fm.popBackStack();
}
}
}
fragment_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/frame_main"
android:layout_width="match_parent"
android:layout_height="match_parent"></FrameLayout>
</RelativeLayout>
LoginFragment.java
public class LoginFragment extends Fragment {
private View mView;
public static LoginFragment newInstance() {
LoginFragment loginFragment = new LoginFragment();
return loginFragment;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_login, container, false);
Log.e("LoginFragment", "onCreateView");
mView.findViewById(R.id.btnLogin).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((MainActivity) getActivity()).replaceInMainFragment(Fragment1.newInstance());
}
});
return mView;
}
}
fragment_login.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/btnLogin"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="Login" />
</RelativeLayout>
Fragment1.java
public class Fragment1 extends Fragment {
private View mView;
public static Fragment1 newInstance() {
Fragment1 fragment1 = new Fragment1();
return fragment1;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_1, container, false);
mView.findViewById(R.id.btnFrag1).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((MainActivity) getActivity()).replaceInMainFragment(Fragment2.newInstance());
}
});
return mView;
}
}
fragment_1.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/btnFrag1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="This is Fragment 1" />
</RelativeLayout>
Fragment2.java
public class Fragment2 extends Fragment {
private View mView;
public static Fragment2 newInstance() {
Fragment2 fragment1 = new Fragment2();
return fragment1;
}
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
mView = inflater.inflate(R.layout.fragment_2, container, false);
mView.findViewById(R.id.btnFrag2).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
}
});
return mView;
}
}
fragment_2.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/btnFrag2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="This is fragment 2" />
</RelativeLayout>
Hope it helps someone.
OLD
Then I think you need some hack. It will not directly accessible. Try calling 2nd activity when user press back button or any other option to go to the 2nd activity from 3rd activity. Hope it suits your app's requirement.
ThirdActivity.java
public class ThirdActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_third);
}
#Override
public void onBackPressed() {
super.onBackPressed();
startActivity(new Intent(getBaseContext(), SecondActivity.class));
}
}
SecondActivity.java
public class SecondActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
findViewById(R.id.btnJumpToThirdScreen).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(getBaseContext(), ThirdActivity.class));
}
});
}
}
OLD
Here is the demo I made just now. For this you need to define android:noHistory="true" in your manifest. Here is the sample code:
MainActivity.java
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.btnJump).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
startActivity(new Intent(getBaseContext(), SecondActivity.class));
}
});
}
}
SecondActivity.java
public class SecondActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_second);
}
}
Manifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.ccc.stackoverflow">
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".SecondActivity"
android:noHistory="true"></activity>
</application>
</manifest>
activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/btnJump"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:text="My Launcher Activity Main" />
</RelativeLayout>
Try this demo. Also check removing noHistory flag from your Manifest. You can see the difference. Hope it helps you.
You should change your app design! Users do not want the app restarted every time they step out. They may lose some work.
You should rather use a sign-in dialog, or fragment, that is displayed above the current activity, every time user returns after app goes to background.
If you call the method:
finish();
In your life cycle methods it will work but It will have a disadvantage too:
The advantage is that when the user clicks "back" the activity will be destroyed and the user will have to put the password again.
The disadvantage is that when the user go to another app may be due to a click in the notification. After finishing using that other app, when the user clicks "back" he wont find your activity! He will have to go to a launcher and click your app icon again. This is not good for users for because they will have to click your app from launcher each time they leave the app.
BEST WAY
Declare a boolean in your Activity call it for example:
private boolean hasUserReturned=false;
Then in your onPause() method:
#Override
protected void onPause() {
super.onPause();
hasUserReturned=true;
}
Then in your onResume() nethod:
#Override
protected void onResume() {
super.onResume();
if(hasUserReturned){
recreate();
}
}
This will recreate your activity each time the user revisit your app. It handles "back button" clicks without removing your activity from backstack!
you should just follow life cycle of android,
when user press back button >> onStop() and onDestroy() called
when use press Home button >> onStop() called
when user again back to open application without more waiting and clean from stack(clear background data) >> called onRestart() called
and if user close the application and also remove application from background then it call >> onCreate()
Now just you find your point while following the life cycle of Android :-)
Solution One: apply code in onStop()
Intent intent = new Intent(this, A.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
finish();
OR
Solution Two: In AndroidManifest.xml file put android:launchMode="singleTask" in to all Activity
like above
<activity
android:name=".Activity.BookingConfirmClass"
android:label="#string/string_confrim_booking"
android:launchMode="singleTask"
android:parentActivityName=".Activity.HotelDetailsClass"
android:screenOrientation="portrait" />
I could suggest you one approach,
Make all your activities extend from one BaseActivity
Add a variable in BaseActivity
public static boolean HAS_RESUMED_FROM_ACTIVITY=false;
and then override startActivity in your BaseActivity like
#Override
startActivity(Intent intent){
HAS_RESUMED_FROM_ACTIVITY=true;
super.startActivity(intent);
}
Now in onResume of your activities you
#Override
protected void onResume(){
if(!BaseActivity.HAS_RESUMED_FROM_ACTIVITY){
//show your lock screen
}
super.onResume();
}
I have a MainActivity and a HomeTabs with three tabs (A B C), i set a refresh on tab C .
My structure is when i trigger onRefresh on tab C , i will switch to MainActivity
and load the data again to show the HomeTabs.
My problem is when i click back for finish(); , the layout will show tab C.
I try to finish the Fragment use like:
getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();
or
((MainActivity)getActivity()).removeFragment(getActivity());
Both of them are no working , when i click back , i still can't finish the app immediately.
Some one can teach me what step i miss it , that would be appreciated.
My HomeTabs extends Fragment it use ViewPager and TabLayout add three tabs
MainActivity:
public class MainActivity extends AppCompatActivity {
private FrameLayout frameLayout;
private Toolbar toolBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
frameLayout = (FrameLayout) findViewById(R.id.frameLayout);
// Load the main Fragment
if (savedInstanceState == null) {
switchFragment(HomeTabs.newInstance());
}
//take the onRefresh data,send data to HomeTabs and open tab C
if (getIntent().hasExtra("refresh")) {
boolean isRefresh = getIntent().getExtras().getBoolean("refresh");
if (isRefresh) {
Bundle bundle = new Bundle();
bundle.putBoolean("refresh", isRefresh);
HomeTabs homeTabs = new HomeTabs();
homeTabs.setArguments(bundle);
switchFragment(homeTabs);
}
}
}
public void switchFragment(Fragment fragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.frameLayout, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
// I try to finsh my tab C , it's no working
public void removeFragment(Activity activity) {
activity.onBackPressed();
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
new DialogHandler(this).quickDialog(
getResources().getString(R.string.quick),
getResources().getString(R.string.confirm),
getResources().getString(R.string.cancel),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// If i onRefrsh three times , i will finsh three times... here is my issue.
finish();
}
}, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
}
return super.onKeyDown(keyCode, event);
}
}
Here is my tab C Fragment refresh call back method:
public class MyLineChart extends Fragment implements SwipeRefreshLayout.OnRefreshListener{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_my_line_chart, container, false);
//.....................
return view;
}
#Override
public void onRefresh() {
refreshLayout.setRefreshing(false);
// Both of them are no working.
//((MainActivity)getActivity()).removeFragment(getActivity());
//getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();
Intent intent = new Intent(getActivity(),MainActivity.class);
intent.putExtra("refresh", true);
startActivity(intent);
}
Finally my HomeTabs Fragment take the date and show tab C:
Bundle bundle = getArguments();
if (bundle != null) {
boolean isRefresh = bundle.getBoolean("refresh");
if (isRefresh) {
//tab C position is 2
tabLayout.getTabAt(2).select();
}
}
Try this solution to add below code when you are starting activity again on Refresh click:-
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
OR
Update your MainActivity.java
1) Add function in MainActivity
public void refreshFragment() {
Bundle bundle = new Bundle();
bundle.putBoolean("refresh", isRefresh);
HomeTabs homeTabs = new HomeTabs();
homeTabs.setArguments(bundle);
switchFragment(homeTabs);
}
Now Call that from Fragment Tab C just replacing startActivity(refresh) code:
MainActivity mainActivity = (MainActivity) getActivity();
mainActivity.refreshFragment();
you can add a listener in your fragment that can trigger a function in your parent activity
which means you need to add an interface in your fragmentC code
public class MyLineChart extends Fragment implements SwipeRefreshLayout.OnRefreshListener {
private MyLineChartListener fragmentListener;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_my_line_chart, container, false);
//.....................
return view;
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
if (context instanceof MyLineChartListener) {
fragmentListener = (MyLineChartListener) context;
} else {
// throw an error
}
}
#Override
public void onRefresh() {
refreshLayout.setRefreshing(false);
// Both of them are no working.
//((MainActivity)getActivity()).removeFragment(getActivity());
//getActivity().getSupportFragmentManager().beginTransaction().remove(this).commit();
fragmentListener.onSettingRefresh();
}
public interface MyLineChartListener {
void onSettingRefresh();
}
}
then you need to implement the listener in the MainActivity code as follows
public class MainActivity extends AppCompatActivity implements MyLineChart.MyLineChartListener {
private FrameLayout frameLayout;
private Toolbar toolBar;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
frameLayout = (FrameLayout) findViewById(R.id.frameLayout);
// Load the main Fragment
if (savedInstanceState == null) {
switchFragment(HomeTabs.newInstance());
}
}
public void switchFragment(Fragment fragment) {
FragmentManager manager = getSupportFragmentManager();
FragmentTransaction transaction = manager.beginTransaction();
transaction.replace(R.id.frameLayout, fragment);
transaction.addToBackStack(null);
transaction.commit();
}
// I try to finsh my tab C , it's no working
public void removeFragment(Activity activity) {
activity.onBackPressed();
}
// this function will be called when the fragment is refreshed
#Override
public void onSettingRefresh() {
Bundle bundle = new Bundle();
bundle.putBoolean("refresh", true);
HomeTabs homeTabs = new HomeTabs();
homeTabs.setArguments(bundle);
switchFragment(homeTabs);
}
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if (keyCode == KeyEvent.KEYCODE_BACK) {
new DialogHandler(this).quickDialog(
getResources().getString(R.string.quick),
getResources().getString(R.string.confirm),
getResources().getString(R.string.cancel),
new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
// If i onRefrsh three times , i will finsh three times... here is my issue.
finish();
}
}, new DialogInterface.OnClickListener() {
#Override
public void onClick(DialogInterface dialog, int which) {
}
});
}
return super.onKeyDown(keyCode, event);
}
}
I have a ViewPager in my MainActivity. Every page in it is a Fragment. So, everytime I swipe right or left, a new instance of the fragment is created and the fragment view is updated accordingly.
I also have two buttons: LEFT and RIGHT for navigation. These buttons are inside the Fragment, not in the Activity. A user can either swipe or alternatively press the relevant button to navigate between the pages.
Here's the problem: Since I'm changing the views through my MainActivity, how do I detect the onClick events of those buttons in the Activity in order to update the fragment?
Here's the PagerAdapter class (Removed all the irrelevant code from everywhere):
public class SectionsPagerAdapter extends FragmentPagerAdapter {
public SectionsPagerAdapter(FragmentManager fm) {
super(fm);
}
#Override
public Fragment getItem(int position) {
// logic part for the views.
return PlaceholderFragment.newInstance(sectionNumber, questionStatus, questionOrder, showNext, showPrevious);
}
And here's the PlaceHolderFragment class:
public class PlaceholderFragment extends Fragment{
//some global variables
public static PlaceholderFragment newInstance(int sectionNumber, int questionStatus, String questionOrder, boolean showNext, boolean showPrevious) {
PlaceholderFragment fragment = new PlaceholderFragment();
//setting up the arguments
fragment.setArguments(args);
return fragment;
}
public PlaceholderFragment() {
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.explanation_fragment, container, false);
//code for filling up all the views
RightButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//can I do something here?
}
});
return rootView;
}
}
MORE INFO:
I have to keep the navigation buttons in the fragment itself and not in the activity.
In your fragment write one interface like:
public class PlaceholderFragment extends Fragment{
private OnButtonClickListener mOnButtonClickListener;
interface OnButtonClickListener{
void onButtonClicked(View view);
}
#Override
public void onAttach(Context context) {
super.onAttach(context);
try {
mOnButtonClickListener = (OnButtonClickListener) context;
} catch (ClassCastException e) {
throw new ClassCastException(((Activity) context).getLocalClassName()
+ " must implement OnButtonClickListener");
}
}
yourButtons.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
mOnButtonClickListener.onButtonClicked(v);
}
});
}
And in your mainactivity:
class MainActivity extends AppCompatActivity implements OnButtonClickListener{
#Override
void onButtonClicked(View view){
int currPos=yourPager.getCurrentItem();
switch(view.getId()){
case R.id.leftNavigation:
//handle currPos is zero
yourPager.setCurrentItem(currPos-1);
break;
case R.id.rightNavigation:
//handle currPos is reached last item
yourPager.setCurrentItem(currPos+1);
break;
}
}
}
For Kotlin and ViewPager2
previous page:
val currPos: Int = xyzViewPager.currentItem
if (currPos != 0) {
xyzViewPager.currentItem = currPos - 1
}
next page:
val currPos: Int = xyzViewPager.currentItem
if ((currPos + 1) != xyzViewPager.adapter?.count) {
xyzViewPager.currentItem = currPos + 1
}
Use kotlin extension functions:
fun ViewPager2.nextPage(smoothScroll: Boolean = true): Boolean {
if ((currentItem + 1) < adapter?.itemCount ?: 0) {
setCurrentItem(currentItem + 1, smoothScroll)
return true
}
//can't move to next page, maybe current page is last or adapter not set.
return false
}
fun ViewPager2.previousPage(smoothScroll: Boolean = true): Boolean {
if ((currentItem - 1) >= 0) {
setCurrentItem(currentItem - 1, smoothScroll)
return true
}
//can't move to previous page, maybe current page is first or adapter not set.
return false
}
Make a public method in your activity
public void swipeRight(int x){
if(x < totalNumberOfFragment){
viewPager.setCurrentItem(x + 1);
}
}
public void swipeLeft(int x){
if(x > 0){
viewPager.setCurrentItem(x - 1);
}
}
You can call these method from your fragment button's click action
RightButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
//Yes
((YourActivityClassName)getActivity()).swipeRight(position);
}
});
And do same for LeftButton
YourActivityClassName - Activity which is holding this viewPager fragment.
position - position of your current fragment.
You can add button in your activities xml as follows
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1" >
<android.support.v4.view.ViewPager
android:id="#+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v4.view.ViewPager>
</LinearLayout>
<ImageView
android:id="#+id/leftNavigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_weight="1"
android:gravity="center"
android:padding="10dp"
android:src="#drawable/ic_chevron_left_black_24dp"
android:visibility="gone" />
<ImageView
android:id="#+id/rightNavigation"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_gravity="right"
android:layout_weight="0"
android:gravity="center"
android:padding="10dp"
android:src="#drawable/ic_chevron_right_black_24dp" />
</FrameLayout>
You can create special method in your parent Activity like following:
public class PagerActiviy extends Activity {
...
public void onFragmentNavigationButtonClick(View button) {
// Do your stuff here
}
...
}
Then in your fragments you can get your parent Activity with getActivity() method, cast it to the actual type and call the method:
public class PlaceholderFragment extends Fragment{
...
...
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.explanation_fragment, container, false);
//code for filling up all the views
RightButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
((PagerActvity) getActivity()).onFragmentNavigationButtonClick(v);
}
});
return rootView;
}
}
As a side note I should add that from your example it's not clear why do you need to keep your navigation buttons in the fragments and can't move them to the Activity and manage them there.
You can send a broadcast upon button click inside the fragment like below:
Intent intent = new Intent();
intent.setAction(NUMBER_OF_RECEIVER_NEXT);
getActivity().sendBroadcast(intent);
Then in your main activity you catch the Intent and you set the current position of the pager to the desired number
private class broadcastReceived extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
String actionGet = intent.getAction();
if(actionGet.equals(NUMBER_OF_RECEIVER_NEXT)){
mPager.setCurrentItem(1);
Log.e("IntentNextPage","Received");
}
}
}
Do not forget to set a
private static final String NUMBER_OF_RECEIVER_NEXT = "nextPage";
in both main activity and fragment and of course to register,unregister receiver to onResume and onPause methods.
Also add an intent filter to the receiver in onCreate methd with the action specified as NUMBER_OF_RECEIVER_NEXT
I am using fragments,I have an edittext in fragment and I want to get value in main activity.
This is my fragment layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:background="#878787" >
<TextView android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="dfgdfgdf"
android:textSize="20dp"
android:layout_centerInParent="true"
android:id="#+id/user_name"/>
<EditText
android:id="#+id/message"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
/>
<Button
android:text="Gönder"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:onClick="getFromUser"
android:layout_marginTop="40dp"
/>
</RelativeLayout>
I am loading fragment with this function:
public void startChat(JsonObject user) {
FrameLayout layout = (FrameLayout)findViewById(R.id.container);
layout.setVisibility(View.VISIBLE);
Bundle bundle = new Bundle();
bundle.putString("name", user.get("name").getAsString());
sendTo=user.get("username").getAsString();
FragmentManager fragmentManager = getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
ConversationFragment conv = new ConversationFragment();
conv.setArguments(bundle);
fragmentTransaction.add(R.id.container, conv);
fragmentTransaction.commit();
viewPager.setVisibility(View.GONE);
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
actionBar.setDisplayHomeAsUpEnabled(true);
}
And this is my fragment class
public class ConversationFragment extends Fragment {
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
String name = getArguments().getString("name");
View rootView = inflater.inflate(R.layout.fragment_conversation, container, false);
TextView username=(TextView)rootView.findViewById(R.id.user_name);
username.setText(name);
return rootView;
}
}
As you can see when press the button main activity runs "getFromUser" function.I want to get edittext value in this function.How can I do this ?
It's always the same procedure for these things. You can't access a fragment's views just like that. You need a callback method.
Add this code to ConversationFragment:
private OnGetFromUserClickListener mListener;
#Override
public void onAttach(Activity activity) {
super.onAttach(activity);
try {
mListener = (OnGetFromUserClickListener ) activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString() + " must implement OnGetFromUserClickListener");
}
}
public void getFromUser(View v) {
if (mListener != null) {
EditText edit = (EditText)findViewById(R.id.message);
mListener.getFromUser(edit.getText().toString());
}
}
public interface OnGetFromUserClickListener {
void getFromUser(String message);
}
Make your MainActivity implement this interface. Replace getFromUser() inside MainActivity with:
public void getFromUser(String message) {
sendMessage(message);
}
Done.
Edit:
Actually, using the XML-onClick attribute is currently bugged (see onClick inside fragment called on Activity): It links to the activity instead of the fragment. You have to set the click listener programmatically to make sure the code won't break at some point in the future. So give the button an ID inside the XML (e.g. get_from_user) and add this code to onCreateView inside ConversationFragment:
v.findViewById(R.id.get_from_user).setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (v.getId() == R.id.get_from_user) {
getFromUser(v);
}
}
});
Using this code vastly decouples the activity and the fragment from each other.
I resolved this problem.
public void getFromUser(View view) {
ConversationFragment fragment1 = (ConversationFragment)getSupportFragmentManager().findFragmentById(R.id.container);
View frag=fragment1.getView();
EditText editText1 =(EditText) frag.findViewById(R.id.message);
String message=editText1.getText().toString();
sendMessage(message);
}
Now I can get edittext value from fragment.
I'm having troubles accessing the Views that within my Fragment. In the example below, I can't access the 2nd button that is within the Fragment (e.g., findViewById appears to return NULL and the app crashes when I try b2.setText("test") ), but when I directly add it in the activity_main.xml, it does work.
Here is the code:
MainActivity.java
public class MainActivity extends Activity
{
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final Button fragmentButton = (Button)findViewById(R.id.iMainButton);
FragmentManager fm = getFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(R.id.iMainInnerLLContainer, new TestFragment());
ft.commit();
final Button b2 = (Button)findViewById(R.id.iTestFragmentInnerButton);
if(b2 == null) { Log.d("MainActivity.java:", "b2 is null"); }
else { Log.d("MainActivity.java:", "b2 is NOT null"); }
fragmentButton.setOnClickListener(new View.OnClickListener()
{
#Override
public void onClick(View v)
{
// do stuff here
}
});
}
}
activity_main.xml
<LinearLayout 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"
android:id="#+id/iMainRootLinearLayoutContainer"
android:orientation="vertical"
>
<Button
android:id="#+id/iMainButton"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="Add fragment..."
/>
<LinearLayout
android:id="#+id/iMainInnerLLContainer"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:orientation="vertical"
>
<!-- Fragment goes here, can reference button if it is added here manually -->
</LinearLayout>
</LinearLayout>
TestFragment.java
public class TestFragment extends Fragment
{
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.ltestfragment, container, false);
}
}
ltestfragment.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="#+id/iTestFragmentOuterLinearLayout"
>
<Button
android:id="#+id/iTestFragmentInnerButton"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:text="This is my test fragment button."
/>
</LinearLayout>
I think I'm missing something very basic here and I would appreciate some insight on what that might be.
Thank you in advance!
I think you need to set up a textchangelistener in your fragment.
public class FragmentA extends Fragment {
TextChangeListener listener;
public interface TextChangeListener {
public void onTextChange(CharSequence newText);
}
public void setTextChangeListener(TextChangeListener listener) {
this.listener = listener;
}
Then, in your activity, set up the listener :
public class ActivityAB extends FragmentActivity {
FragmentA fragmentA;
FragmentB fragmentB;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ab);
FragmentManager manager = getSupportFragmentManager();
fragmentA = (FragmentA) manager.findFragmentById(R.id.fragmentA);
fragmentB = (FragmentB) manager.findFragmentById(R.id.fragmentB);
fragmentA.setTextChangeListener(new TextChangeListener() {
#Override
public void onTextChange(CharSequence newText) {
fragmentB.updateTextValue(newText);
}
});
}
}
Implement an interface to listen to the events of a fragment from its activity.
Code in Fragment:-
public class TestFragment extends Fragment
{
public interface OnClickListener
{
public void onButtonClicked(<data type><data>);
}
b2.setOnClickListener(new OnClickListener() {
#Override
public void onClick(View v) {
listener.onButtonClicked(<<pass some values here>>);
}
});
}
Code in Main:-
MainActivity extends FragmentActivity implements TestFragment.OnClickListener,
{
#Override
public void onButtonClicked(<<receive the pased data here>>) {
//do some stuff here with the received data after the button is clicked
}
}